委托具有以下属性:
委托类似于 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