2017/9/10 17:42:36 易思捷科技
通过前面的讲解,我们应该了解,委托,就是在调用了一个定义好的引用方法。这个方法可以通过命名方法形式,由其它类创建,或是静态方法,也可以通过匿名方法来实现,有关lambda,我们会专门开篇文章对其进行讲解。因此在委托章节中将会跳过lambda。
先来看看匿名方法,匿名方法最大的好处应该是为编码带来了益处,节约了时间。其它方面。另外,从代码的可读性上来看,也更加友好了。
继续委托的讲解,讲到委托,通常离不开事件。采用微软官方的说法,委托可以定义回调,委托是事件的基础。下面先讲讲回调。先看看回调的概念。
首先回调,它不是一种技术,而是一种方式、机制。其实现的目的是为了让被调用者可以调用调用者的一些方法。譬如:在Class-A中,实例化了Class-B,这样A调用了B,A可以访问B公开的方法,但B此时想调用A的一些方法,或者通知A去做一些事情时,却无能为力,于是回调出现了。(重点:我们认为回调是一种机制,是一种调用机制,在不同的技术平台中,实现回调的方法和技术也都不同,除了回调,还有同步调用和异步调用。但有些文章中,讲到了回调函数就是回调,因此将回调函数作为了回调的定义,我们认为这是错误的。)
我们找了很多回调的概念,但都没有找到很官方的说法。因此大家可以参考百度百科的说法。回调是一个很常用的机制。在面向过程,结构化编程的时候,回调就出现了,于是经常可以看到的就是回调函数,回调函数是实现回调的一种具体的技术。
在面向对象中,.Net可以通过委托来实现回调,上一篇的讲解,大家可以仔细理解,再看红色字体,委托可以定义回调。在Java领域中,则是通过接口来实现。所以,回调是一种机制,在不同的技术平台中,具体实现的技术与方法都不相同。在Js中,就是回调函数了。回调的具体实现,我们在《回调》一章节中,还会讲到,在此就不再细说。
下面开始讲讲在很多场景中都与委托并存的事件。
事件:是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知。(此定义来源于https://docs.microsoft.com/zh-cn/dotnet/csharp/events-overview)。事件的概念很容易理解,就是一种消息通知机制,通知已经发生的事件。
以.Net平台C#为例,先讲解事件,稍后,以Java为例,讲解事件。
事件为何放到了委托中讲解,因为事件是一种特殊的多播委托,只能从声明它的类中进行调用。.NET Framework 类库中的所有事件均基于 EventHandler 委托,定义如下:
public delegate void EventHandler(object sender, EventArgs e);
参数列表包含两种参数:发件人和事件参数。sender
的编译时类型为 System.Object
,即使有一个始终正确的更底层派生的类型亦是如此。 按照惯例使用 object
。
第二种参数通常是派生自 System.EventArgs
的类型。 (在下一部分中此约定不再强制执行。)即使事件类型无需任何其他参数,你仍将提供这两种参数。
应使用特殊值 EventArgs.Empty
来表示事件不包含任何附加信息。
下面看看如果定义一个事件,并使用它,首先先定义一个事件。
public event EventHandler RaiseCustomEvent;
如果我们需要在这个事件中传递一些信息的话,可以继承EventArgs,自定义一个类来实现数据传递,在此我们省略此环节。
紧接着,我们可以订阅此时间,订阅事件可以通过+=来处理,如下:
pub.RaiseCustomEvent += HandleCustomEvent;
在HandleCustomEvent方法中,写入您处理此事件的自定义代码。
看下完整的代码,此代码为微软官方案例,请参考:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/how-to-publish-events-that-conform-to-net-framework-guidelines。
namespace DotNetEvents { using System; using System.Collections.Generic; // Define a class to hold custom event info public class CustomEventArgs : EventArgs { public CustomEventArgs(string s) { message = s; } private string message; public string Message { get { return message; } set { message = value; } } } // Class that publishes an event class Publisher { // Declare the event using EventHandler<T> public event EventHandler<CustomEventArgs> RaiseCustomEvent; public void DoSomething() { // Write some code that does something useful here // then raise the event. You can also raise an event // before you execute a block of code. OnRaiseCustomEvent(new CustomEventArgs("Did something")); } // Wrap event invocations inside a protected virtual method // to allow derived classes to override the event invocation behavior protected virtual void OnRaiseCustomEvent(CustomEventArgs e) { // Make a temporary copy of the event to avoid possibility of // a race condition if the last subscriber unsubscribes // immediately after the null check and before the event is raised. EventHandler<CustomEventArgs> handler = RaiseCustomEvent; // Event will be null if there are no subscribers if (handler != null) { // Format the string to send inside the CustomEventArgs parameter e.Message += String.Format(" at {0}", DateTime.Now.ToString()); // Use the () operator to raise the event. handler(this, e); } } } //Class that subscribes to an event class Subscriber { private string id; public Subscriber(string ID, Publisher pub) { id = ID; // Subscribe to the event using C# 2.0 syntax pub.RaiseCustomEvent += HandleCustomEvent; } // Define what actions to take when the event is raised. void HandleCustomEvent(object sender, CustomEventArgs e) { Console.WriteLine(id + " received this message: {0}", e.Message); } } class Program { static void Main(string[] args) { Publisher pub = new Publisher(); Subscriber sub1 = new Subscriber("sub1", pub); Subscriber sub2 = new Subscriber("sub2", pub); // Call the method that raises the event. pub.DoSomething(); // Keep the console window open Console.WriteLine("Press Enter to close this window."); Console.ReadLine(); } } }
逐一分析以上代码内容
为了可以在事件中传递消息,因此定义了一个CustomEventArgs类,从EventArgs派生而出。
然后定义了两个类,publisher和subscriber,publisher是发布类,并且定义了一个事件,在方法dosomething中触发这个事件,subscriber这个类中则订阅了这个事件,并在handlecustomevent方法中,接收这个通知消息,并进行处理。
看下main,实例化publisher,并实例化sub,调用dosomthing,改如何执行呢?
不看结果,猜一下,猜对了,事件也就基本入门了。
版权声明:如无特别说明,均为“易思捷IT训练营”原创,如转载请著名出处!