事件和委托的区别到底是什么
揭秘事件
一探究竟
在控制台程序中定义一个事件OrderCompleted
internal class Program
{
/// <summary>
/// 订单完成事件
/// </summary>
public event EventHandler OrderCompleted;
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
编译下,通过ILSpy查看最终编译代码是什么
// Fields
.field private class [System.Runtime]System.EventHandler OrderCompleted
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
// Events
.event [System.Runtime]System.EventHandler OrderCompleted
{
.addon instance void demoForConsoleEvent31.Program::add_OrderCompleted(class [System.Runtime]System.EventHandler)
.removeon instance void demoForConsoleEvent31.Program::remove_OrderCompleted(class [System.Runtime]System.EventHandler)
}
实际上,它会编译器编译为一个私有的属性字段,并添加了addon和removeon两个公开方法。
EventHandler是什么
.class public auto ansi sealed System.EventHandler
extends System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method EventHandler::.ctor
...
}
我们看到,实际上System.EventHandler
扩展自System.MulticastDelegate
(多播委托),所以它本质就是委托。
而这个System.MulticastDelegate
又是什么?我们进一步看看
.class public auto ansi abstract serializable beforefieldinit System.MulticastDelegate
extends System.Delegate
{
.custom instance void System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 01 00 00
)
// Fields
.field private object _invocationList
.field private native int _invocationCount
...
}
这不就是个委托类型System.Delegate
System.MulticastDelegate
(多播委托)相比System.Delegate
来说,具有一个带有链接的委托列表(_invocationList
),称为调用列表,在对委托实例进行调用的时候,将按列表中的委托顺序进行同步调用。
我们可以直接通过GetInvocationList
方法获取到这个列表
Delegate[] list = OrderCompleted.GetInvocationList();
事件的本质
事件本质上,一组成对的Add/Remove的公开方法和一个包含委托类型对象(System.EventHandler
)的私有字段。
使用事件
public partial class Form1 : Form
{
/// <summary>
/// 订单完成事件
/// </summary>
public event EventHandler OrderCompleted;
public Form1()
{
InitializeComponent();
OrderCompleted -= Form1_OrderCompleted;
OrderCompleted += Form1_OrderCompleted;
}
private void Form1_OrderCompleted(object sender, EventArgs e)
{
}
protected override void onl oad(EventArgs e)
{
OrderCompleted.Invoke(this, e);
base.OnLoad(e);
}
}
其中-=
和+=
最终被编译为
// OrderCompleted -= Form1_OrderCompleted;
IL_0015: nop
IL_0016: ldarg.0
IL_0017: ldarg.0
IL_0018: ldftn instance void demoForFormEvent31.Form1::Form1_OrderCompleted(object, class [mscorlib]System.EventArgs)
IL_001e: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
IL_0023: call instance void demoForFormEvent31.Form1::remove_OrderCompleted(class [mscorlib]System.EventHandler)
// OrderCompleted += Form1_OrderCompleted;
IL_0028: nop
IL_0029: ldarg.0
IL_002a: ldarg.0
IL_002b: ldftn instance void demoForFormEvent31.Form1::Form1_OrderCompleted(object, class [mscorlib]System.EventArgs)
IL_0031: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
IL_0036: call instance void demoForFormEvent31.Form1::add_OrderCompleted(class [mscorlib]System.EventHandler)
实际上这里是新建了一个System.EventHandler
类型的委托实例,和Form1_OrderCompleted
进行关联,最终是响应了remove_OrderCompleted
和add_OrderCompleted
方法。
触发事件
在OnLoad
方法中,我们对这个事件进行了一次触发OrderCompleted.Invoke(this, e)
,我们看看最终变成了什么
// this.OrderCompleted(this, e);
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.EventHandler demoForFormEvent31.Form1::OrderCompleted
IL_0007: ldarg.0
IL_0008: ldarg.1
IL_0009: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, class [mscorlib]System.EventArgs)
实际上本质是,获取了事件包含的System.EventHandler
类型委托,并调用了委托自带的触发方法Invoke
。
这里OrderCompleted.Invoke(this, e)
其实最终变成了
namespace System
{
[Serializable]
[ComVisible(true)]
public delegate void EventHandler(object sender, EventArgs e);
}
事件参数
这里我们设计到一个事件参数,名为System.EventArgs
,看看它是什么。
.class public auto ansi serializable beforefieldinit System.EventArgs
extends System.Object
{
.custom instance void System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 01 00 00
)
// Fields
.field public static initonly class System.EventArgs Empty
....
}
其本质也就是一个对象,类型是System.Object
。
揭秘委托
一探究竟
在控制台程序中定义一个委托OrderOption
internal class Program
{
/// <summary>
/// 订单选项委托
/// </summary>
public delegate void OrderOption();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
编译下,通过ILSpy查看最终编译代码是什么
// Nested Types
.class nested public auto ansi sealed OrderOption
extends [System.Runtime]System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method OrderOption::.ctor
.method public hidebysig newslot virtual
instance void Invoke () runtime managed
{
} // end of method OrderOption::Invoke
.method public hidebysig newslot virtual
instance class [System.Runtime]System.IAsyncResult BeginInvoke (
class [System.Runtime]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method OrderOption::BeginInvoke
.method public hidebysig newslot virtual
instance void EndInvoke (
class [System.Runtime]System.IAsyncResult result
) runtime managed
{
} // end of method OrderOption::EndInvoke
} // end of class OrderOption
首先我们看到OrderOption
是一个类(Class),其次它的基类是System.MulticastDelegate
(多播委托),这就证明其实委托本质是一个类,它是可以被实例化的。
并且它自带三个方法:Invoke
、BeginInvoke
、EndInvoke
。
使用委托
前面清楚知道了委托其实本质是一个类,那我们使用它就先要将它实例化,再调用内部的方法。
/// <summary>
/// 订单选项委托
/// </summary>
public delegate void OrderOption();
private void Form1_OrderCompleted(object sender, EventArgs e)
{
var orderOption = new OrderOption(InitOrderOption);
orderOption.Invoke();
}
public void InitOrderOption()
{
}
这里实例化了一个OrderOption
,并且我们需要在构造函数这里将参数传进去,这里我们构建了一个参数是InitOrderOption
方法,最后我们调用这个实例的Invoke
方法。
来看看这段代码最终变成了啥
.method private hidebysig
instance void Form1_OrderCompleted (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
{
// {
IL_0000: nop
// OrderOption orderOption = InitOrderOption;
IL_0001: ldarg.0
IL_0002: ldftn instance void demoForFormEvent31.Form1::InitOrderOption()
IL_0008: newobj instance void demoForFormEvent31.Form1/OrderOption::.ctor(object, native int)
IL_000d: stloc.0
// orderOption();
IL_000e: ldloc.0
IL_000f: callvirt instance void demoForFormEvent31.Form1/OrderOption::Invoke()
// }
IL_0014: nop
IL_0015: ret
} // end of method Form1::Form1_OrderCompleted
.method public hidebysig
instance void InitOrderOption () cil managed
{
} // end of method Form1::InitOrderOption
可以看到,当我们通过构造函数将InitOrderOption
传进去之后,它最终其实变成了一个基于InitOrderOption
创建一个新OrderOption
实例的动作。
然后Invoke
的时候确实是调用了OrderOption
实例内部的Invoke
方法。
使用匿名委托
我们知道委托我们还可以通过匿名方法(Anonymous Methods)的方式来使用,匿名方法没有名称只有方法主体,可以写成这样
/// <summary>
/// 订单选项委托
/// </summary>
public delegate void OrderOption();
private void Form1_OrderCompleted(object sender, EventArgs e)
{
new OrderOption(() =>
{
Console.WriteLine("123");
}).Invoke();
}
上诉我们使用了Lambda
表达式的写法,看看最终它变成什么样子了
.method private hidebysig
instance void Form1_OrderCompleted (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
{
// {
IL_0000: nop
// ((OrderOption)delegate
// {
// Console.WriteLine("123");
// })();
IL_0001: ldsfld class demoForFormEvent31.Form1/OrderOption demoForFormEvent31.Form1/'<>c'::'<>9__5_0'
IL_0006: dup
IL_0007: brtrue.s IL_0020
// (no C# code)
IL_0009: pop
IL_000a: ldsfld class demoForFormEvent31.Form1/'<>c' demoForFormEvent31.Form1/'<>c'::'<>9'
IL_000f: ldftn instance void demoForFormEvent31.Form1/'<>c'::'<Form1_OrderCompleted>b__5_0'()
IL_0015: newobj instance void demoForFormEvent31.Form1/OrderOption::.ctor(object, native int)
IL_001a: dup
IL_001b: stsfld class demoForFormEvent31.Form1/OrderOption demoForFormEvent31.Form1/'<>c'::'<>9__5_0'
IL_0020: callvirt instance void demoForFormEvent31.Form1/OrderOption::Invoke()
// }
IL_0025: nop
IL_0026: ret
} // end of method Form1::Form1_OrderCompleted
实际上它也是实例化了一个OrderOption
并调用了它Invoke
方法。