• 收藏

委托 —— 连载 (二)事件

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训练营”原创,如转载请著名出处!

阅读:215  评论:0  
  • 评论