C#中delegate和Event的区别

委托具有以下属性:
委托类似于 C++ 函数指针,但它们是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不必与委托类型完全匹配。

事件具有以下属性:
发行者确定何时引发事件;订户确定对事件作出何种响应。
一个事件可以有多个订户。 订户可以处理来自多个发行者的多个事件。
没有订户的事件永远也不会引发。
事件通常用于表示用户操作,例如单击按钮或图形用户界面中的菜单选项。
当事件具有多个订户时,引发该事件时会同步调用事件处理程序。 若要异步调用事件,请参阅 Calling Synchronous Methods Asynchronously。
在 .NET Framework 类库中,事件基于 EventHandler 委托和 EventArgs 基类。

   /*
     * Event 由本类触发,一个事件可以有多个注册多个接收者,接收者也可以注册到多个事件
     * 事件通常用于表示用户操作
     * 
     * Event 是一种特殊的delegate,在类中使用时,两者是一样的
     * 在类外,delegate不变,Event 不可以被调用或用=赋值,只可以使用-=和+=运算符
     * 
     * 
     */



    public delegate void SampleEventHandle(string e);
    public class Publisher
    {
        /// <summary>
        /// Event 只能在本类中调用,子类也不行
        /// </summary>
        public event SampleEventHandle SampleEvent;

        public SampleEventHandle NoEvent;

        protected void RaiseSampleEvent(string str)
        {
            SampleEvent(str);

            //NoEvent = null;
            //SampleEvent = null;
        }
    }



    class DelegateEvent_Test
    {
        static void Main(string[] args)
        {
            Publisher publisher = new Publisher();

            publisher.NoEvent += TestEvent;  //给delegate赋值。

            publisher.NoEvent("e"); // 调用delegate,没有问题          

            publisher.SampleEvent += TestEvent; // 给event赋值,这没有问题

            //publisher.SampleEvent("e"); //调用event,这个就错了,只能在Publisher内部调用
        }

        private static void TestEvent(string e)
        {
            throw new NotImplementedException();
        }
    }

如果我们想要更深入的了解delegate和Event有什么不同,我们可以查看IL代码。我们将以上代码编译后,用ildasm打开exe文件,生成了如下目录(只看Publisher):
这里写图片描述
我们需要详细了解的就是NoEvent、SampleEvent 字段,add_SampleEvent、remove_SampleEvent方法,还有最后一个SampleEvent事件。毫无疑问,SampleEvent在IL中被分解成了 SampleEvent 字段,add_SampleEvent、remove_SampleEvent方法和SampleEvent事件。而IL中的SampleEvent事件包含add_SampleEvent和remove_SampleEvent两个方法。
将IL代码列出来:

NoEvent

.field public class ConsoleApp1.SampleEventHandle NoEvent

SampleEvent

.field private class ConsoleApp1.SampleEventHandle SampleEvent
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) 

add_SampleEvent

.method public hidebysig specialname instance void 
        add_SampleEvent(class ConsoleApp1.SampleEventHandle 'value') cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // 代码大小       41 (0x29)
  .maxstack  3
  .locals init (class ConsoleApp1.SampleEventHandle V_0,
           class ConsoleApp1.SampleEventHandle V_1,
           class ConsoleApp1.SampleEventHandle V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class ConsoleApp1.SampleEventHandle ConsoleApp1.Publisher::SampleEvent
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  ldarg.1
  IL_000b:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                          class [mscorlib]System.Delegate)
  IL_0010:  castclass  ConsoleApp1.SampleEventHandle
  IL_0015:  stloc.2
  IL_0016:  ldarg.0
  IL_0017:  ldflda     class ConsoleApp1.SampleEventHandle ConsoleApp1.Publisher::SampleEvent
  IL_001c:  ldloc.2
  IL_001d:  ldloc.1
  IL_001e:  call       !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class ConsoleApp1.SampleEventHandle>(!!0&,
                                                                                                                        !!0,
                                                                                                                        !!0)
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  ldloc.1
  IL_0026:  bne.un.s   IL_0007
  IL_0028:  ret
} // end of method Publisher::add_SampleEvent

remove_SampleEvent

.method public hidebysig specialname instance void 
        remove_SampleEvent(class ConsoleApp1.SampleEventHandle 'value') cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // 代码大小       41 (0x29)
  .maxstack  3
  .locals init (class ConsoleApp1.SampleEventHandle V_0,
           class ConsoleApp1.SampleEventHandle V_1,
           class ConsoleApp1.SampleEventHandle V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class ConsoleApp1.SampleEventHandle ConsoleApp1.Publisher::SampleEvent
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  ldarg.1
  IL_000b:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,
                                                                                         class [mscorlib]System.Delegate)
  IL_0010:  castclass  ConsoleApp1.SampleEventHandle
  IL_0015:  stloc.2
  IL_0016:  ldarg.0
  IL_0017:  ldflda     class ConsoleApp1.SampleEventHandle ConsoleApp1.Publisher::SampleEvent
  IL_001c:  ldloc.2
  IL_001d:  ldloc.1
  IL_001e:  call       !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class ConsoleApp1.SampleEventHandle>(!!0&,
                                                                                                                        !!0,
                                                                                                                        !!0)
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  ldloc.1
  IL_0026:  bne.un.s   IL_0007
  IL_0028:  ret
} // end of method Publisher::remove_SampleEvent

SampleEvent

.event ConsoleApp1.SampleEventHandle SampleEvent
{
  .addon instance void ConsoleApp1.Publisher::add_SampleEvent(class ConsoleApp1.SampleEventHandle)
  .removeon instance void ConsoleApp1.Publisher::remove_SampleEvent(class ConsoleApp1.SampleEventHandle)
} // end of event Publisher::SampleEvent

猜你喜欢

转载自blog.csdn.net/lwwl12/article/details/79900613