首页 > 编程语言 >温故知新,CSharp遇见事件和事件(Event/Delegate),从编译后源码的角度来聊本质

温故知新,CSharp遇见事件和事件(Event/Delegate),从编译后源码的角度来聊本质

时间:2022-10-30 18:23:20浏览次数:84  
标签:来聊 温故知新 void System instance Form1 源码 IL OrderCompleted

事件和委托的区别到底是什么

image

揭秘事件

一探究竟

在控制台程序中定义一个事件OrderCompleted

internal class Program
{
    /// <summary>
    /// 订单完成事件
    /// </summary>
    public event EventHandler OrderCompleted;

    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
    }
}

编译下,通过ILSpy查看最终编译代码是什么

image

// 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_OrderCompletedadd_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查看最终编译代码是什么

image

// 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(多播委托),这就证明其实委托本质是一个类,它是可以被实例化的。

并且它自带三个方法:InvokeBeginInvokeEndInvoke

使用委托

前面清楚知道了委托其实本质是一个类,那我们使用它就先要将它实例化,再调用内部的方法。

/// <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方法。

参考

标签:来聊,温故知新,void,System,instance,Form1,源码,IL,OrderCompleted
From: https://www.cnblogs.com/taylorshi/p/16841864.html

相关文章