为什么C#EventHandler等于MSN示例中的事件?

时间:2013-09-09 19:04:27

标签: c# events publish-subscribe

以下是MSN网站的一个示例。这是一个很好的例子,我只是不明白这一行:

EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

正在做什么?

  1. 根据程序顶部的定义,RaiseCustomEvent不是一个事件吗?

  2. 为什么Event等同于EventHandler?这是两种不同的类型。

  3. RaiseCustomEvent在哪里被初始化?如果没有初始化,我们如何复制它,或者为什么我们要将未初始化的东西复制到其他东西?

  4. 那里的handler变量是什么?这是事件还是事件处理程序?

  5. 我很困惑,我正在努力让这个事件/事件处理程序/委托问题得到理解。

    以下是MSN的示例代码

    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();
    
        }
    }
    }
    

2 个答案:

答案 0 :(得分:4)

一个事件是一个委托类型属性是什么属于任何其他类型。

如果你有这样的财产:

public string Name {get;set;}

显然你可以这样做:

string name = Name;

该属性具有由属性访问/修改的基础字符串值。

类似地,事件的底层是委托,该委托是事件声明中定义的类型。它是一个事件,只是定义了如何从该底层委托中添加/删除该事件的处理程序。

从声明类型(这是一个关键点;你不能在外部执行此操作)中,您可以访问该底层委托以调用它。这是执行您看到的代码的原因;他们正在访问底层委托,以便他们可以验证其中是否有一些处理程序,如果是,则调用它们。

所以,明确回答问题:

  

根据程序顶部的定义,RaiseCustomEvent不是一个事件吗?

RaiseCustomEvent是事件包装的基础委托的类型。

  

为什么Event等同于EventHandler?这是两种不同的类型。

这不是严格的平等。它正在从事件中撤出底层代表。

  

RaiseCustomEvent在哪里被初始化?如果没有初始化,我们如何复制它,或者为什么我们要将未初始化的东西复制到其他东西?

在这种情况下,它使用框架将提供的自动添加/删除实现,而不是手动定义它们。如果当前为null,则自动定义的添加处理程序将初始化基础委托。如果事件声明会 定义一个自定义add处理程序,它需要处理这种情况。

  

那里的handler变量是什么?那是一个事件还是事件处理程序?

它是一个代表所有事件处理程序组合的委托。在其定义中将是组成该委托的所有单个方法的调用列表。所以它不是一个单独的事件处理程序,它是所有这些的集合。由于它被淘汰出事件,它不再严格地代表该事件;它是过去某个时刻事件的副本。您无法使用已从中提取的代理更改事件(即添加新处理程序)。

答案 1 :(得分:1)

我会尝试你提出的四个问题:

  

1)RaiseCustomEvent不是基于程序顶部定义的事件吗?

CustomEventArgs类包含我们要声明的事件的一些数据(参数)。它在EventHandler<CustomEventArgs>类型中用作类型参数。最后一种类型是委托类型,这意味着它表示一个或多个具有相同签名和返回类型的方法。 (零方法将是null引用作为委托的值。)

事件RaiseCustomEvent的类型是委托类型EventHandler<CustomEventArgs>

  

2)为什么Event等同于EventHandler?这是两种不同的类型

事件包含一对特殊方法,访问者,一个add访问者和一个remove访问者。两者都有一个相同类型的参数,称为事件的类型。该类型必须是委托类型。在这种情况下,该类型为EventHandler<CustomEventArgs>

在此示例中,事件是所谓的类字段事件。它生成相同类型的后备字段EventHandler<CustomEventArgs>,委托类型。该字段与事件本身具有相同的名称!

当他们这样做时:

// 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;

他们将该支持字段的当前值复制到局部变量handler中。评论描述了原因。他们想在调用委托之前检查null

  

3)RaiseCustomEvent在哪里初始化?如果没有初始化我们如何复制或为什么我们要将未初始化的东西复制到soemthig。

当人们使用事件的add访问者时,它通常会被初始化。这通过特殊的C#语法+=进行。这称为订阅该事件。请参阅Subscriber课程。

实际上pub.RaiseCustomEvent += HandleCustomEvent;会转换为pub.add_RaiseCustomEvent(HandleCustomEvent);,因此它是对add访问者的调用。 add访问器由编译器生成(在类似字段的事件中),并初始化后备字段。

  

4)我不知道什么是处理程序变量?是一个事件或事件处理程序?

这是一名代表。这不是一个事件。它是某个时刻类场事件的后备字段的副本。