温故知新,CSharp遇见事件和委托(Event/Delegate),通过ILSpy反编译代码,透过现象看本质

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

image

委托提供了一种机制,可实现涉及组件间最小耦合度的软件设计,它是一种引用类型

和委托类似,事件是后期绑定机制。事件是建立在对委托的语言支持之上的,它是对委托的封装,可以理解为一种特殊的委托(本质不是)

事件是对象用于广播已发生事情的一种方式。任何其他组件都可以订阅事件,并在事件引发时得到通知。

相同点

  • 它们都提供了一个后期绑定方案:在该方案中,组件通过调用仅在运行时识别的方法进行通信。
  • 它们都支持单个和多个订阅服务器方法。这称为单播和多播支持。
  • 二者均支持用于添加和删除处理程序的类似语法。
  • 引发事件和调用委托使用完全相同的方法调用语法。它们甚至都支持与?.运算符一起使用的相同的Invoke()方法语法。

不同点

  • 用于事件的委托通常没有返回值,如果需要返回值,那么请使用委托。
  • 对事件的侦听是可选的。
  • 事件只能从外部添加和删除响应方法,不能主动触发事件、获取其它注册的响应方法,而委托不受这种限制。

揭秘事件

https://github.com/TaylorShi/HelloEventAndDelegate

一探究竟

在控制台程序中定义一个事件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_OnOrderCompleted;
        OrderCompleted += Form1_OnOrderCompleted;
    }

    private void Form1_OnOrderCompleted(object sender, EventArgs e)
    {

    }

    protected override void OnLoad(EventArgs e)
    {
        OrderCompleted.Invoke(this, e);
        base.OnLoad(e);
    }
}

通常来说,事件的处理程序通过以On作为前缀命名,后跟事件名称。

其中-=+=最终被编译为

// OrderCompleted -= Form1_OnOrderCompleted;
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_OnOrderCompleted;
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_OnOrderCompleted进行关联,最终是响应了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)
{
    OrderOption orderOption = delegate()
    {
        Console.WriteLine("123");
    };
    orderOption.Invoke();
}

看看最终它变成什么样子了

.method private hidebysig
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	IL_0000: nop
	// 	OrderOption 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
	// orderOption();
	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: stloc.0
	IL_0021: ldloc.0
	IL_0022: callvirt instance void demoForFormEvent31.Form1/OrderOption::Invoke()
	// }
	IL_0027: nop
	IL_0028: ret
} // end of method Form1::Form1_OrderCompleted

实际上它也是实例化了一个OrderOption并调用了它Invoke方法。

这样写,这个函数没有名字,但是这个委托需要有个明确的名字。

使用Lamada简写匿名委托

在C#中,我们可以使用Lambda表达式来创建匿名函数。Lambda表达式的左侧是输入参数,中间符号是=>,右侧是匿名函数的主体。

通常可以写成,其中$Input Params可以没有:

($Input Params) => $Expression;
// 或者
($Input Params) => { };
private void Form1_OrderCompleted(object sender, EventArgs e)
{
    OrderOption orderOption = () =>
    {
        Console.WriteLine("123");
    };
    orderOption.Invoke();
}

看看最终它变成什么样子了

.method private hidebysig
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed
{
	IL_0000: nop
	// 	OrderOption 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
	// orderOption();
	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: stloc.0
	IL_0021: ldloc.0
	IL_0022: callvirt instance void demoForFormEvent31.Form1/OrderOption::Invoke()
	// }
	IL_0027: nop
	IL_0028: ret
} // end of method Form1::Form1_OrderCompleted

这里我们看到其本质和前面使用匿名函数是一模一样的,Lambda表达式实际上创造匿名函数的一个语法糖。

使用Func泛型委托

我们知道,通过Func可以构建带返回值的泛型委托。

private void Form1_OrderCompleted(object sender, EventArgs e)
{
    Func<int,int,int> orderSum = (x, y) =>
    {
        return x + y;
    };
    Console.WriteLine(orderSum);
}

Func的用法是,最后一个参数是返回值类型,前面的参数是输入参数的类型。

看看最后编译成啥样

.method private hidebysig 
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	// {
	IL_0000: nop
	// Func<int, int, int> func = (int x, int y) => x + y;
	IL_0001: ldsfld class [mscorlib]System.Func`3<int32, int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'
	IL_0006: dup
	IL_0007: brtrue.s IL_0020

	// (no C# code)
	IL_0009: pop
	// func(1, 2);
	IL_000a: ldsfld class demoForFormEvent31.Form1/'<>c' demoForFormEvent31.Form1/'<>c'::'<>9'
	IL_000f: ldftn instance int32 demoForFormEvent31.Form1/'<>c'::'<Form1_OrderCompleted>b__5_0'(int32, int32)
	IL_0015: newobj instance void class [mscorlib]System.Func`3<int32, int32, int32>::.ctor(object, native int)
	IL_001a: dup
	IL_001b: stsfld class [mscorlib]System.Func`3<int32, int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'

	IL_0020: stloc.0
	IL_0021: ldloc.0
	IL_0022: ldc.i4.1
	IL_0023: ldc.i4.2
	IL_0024: callvirt instance !2 class [mscorlib]System.Func`3<int32, int32, int32>::Invoke(!0, !1)
	IL_0029: pop
	// }
	IL_002a: ret
} // end of method Form1::Form1_OrderCompleted

它最终等价于

Func<int, int, int> func = (int x, int y) => x + y;

其中System.Func的定义,发现它也是基于System.MulticastDelegate多播委托的。

.class public auto ansi sealed System.Func`3<-T1, -T2, +TResult>
	extends System.MulticastDelegate
{
	.custom instance void System.Runtime.CompilerServices.TypeForwardedFromAttribute::.ctor(string) = (
		01 00 4e 53 79 73 74 65 6d 2e 43 6f 72 65 2c 20
		56 65 72 73 69 6f 6e 3d 33 2e 35 2e 30 2e 30 2c
		20 43 75 6c 74 75 72 65 3d 4e 65 75 74 72 61 6c
		2c 20 50 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e
		3d 62 37 37 61 35 63 35 36 31 39 33 34 65 30 38
		39 00 00
	)
	.custom instance void __DynamicallyInvokableAttribute::.ctor() = (
		01 00 00 00
	)
	...
} // end of class System.Func`3

使用Action泛型委托

我们知道,通过Action可以构建无返回值的泛型委托。

private void Form1_OrderCompleted(object sender, EventArgs e)
{
    Action<int, int> orderSum = (x, y) =>
    {
        Console.WriteLine(x + y);
    };
    orderSum.Invoke(1,2);
}

Action的用法是,参数是输入参数的类型,无法返回返回值,其构建的匿名函数都是Void的。

.method private hidebysig 
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	// {
	IL_0000: nop
	// 	Action<int, int> action = delegate(int x, int y)
	// 	{
	// 		Console.WriteLine(x + y);
	// 	};
	IL_0001: ldsfld class [mscorlib]System.Action`2<int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'
	IL_0006: dup
	IL_0007: brtrue.s IL_0020

	// (no C# code)
	IL_0009: pop
	// action(1, 2);
	IL_000a: ldsfld class demoForFormEvent31.Form1/'<>c' demoForFormEvent31.Form1/'<>c'::'<>9'
	IL_000f: ldftn instance void demoForFormEvent31.Form1/'<>c'::'<Form1_OrderCompleted>b__5_0'(int32, int32)
	IL_0015: newobj instance void class [mscorlib]System.Action`2<int32, int32>::.ctor(object, native int)
	IL_001a: dup
	IL_001b: stsfld class [mscorlib]System.Action`2<int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'

	IL_0020: stloc.0
	IL_0021: ldloc.0
	IL_0022: ldc.i4.1
	IL_0023: ldc.i4.2
	IL_0024: callvirt instance void class [mscorlib]System.Action`2<int32, int32>::Invoke(!0, !1)
	// }
	IL_0029: nop
	IL_002a: ret
} // end of method Form1::Form1_OrderCompleted

它最终等价于

Action<int, int> action = delegate(int x, int y)
{
	Console.WriteLine(x + y);
};

其中System.Action的定义,发现它也是基于System.MulticastDelegate多播委托的。

.class public auto ansi sealed System.Action`2<-T1, -T2>
	extends System.MulticastDelegate
{
	.custom instance void System.Runtime.CompilerServices.TypeForwardedFromAttribute::.ctor(string) = (
		01 00 4e 53 79 73 74 65 6d 2e 43 6f 72 65 2c 20
		56 65 72 73 69 6f 6e 3d 33 2e 35 2e 30 2e 30 2c
		20 43 75 6c 74 75 72 65 3d 4e 65 75 74 72 61 6c
		2c 20 50 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e
		3d 62 37 37 61 35 63 35 36 31 39 33 34 65 30 38
		39 00 00
	)
	.custom instance void __DynamicallyInvokableAttribute::.ctor() = (
		01 00 00 00
	)

} // end of class System.Action`2

揭秘匿名类型

什么是匿名类型

匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型。类型名由编译器生成,并且不能在源代码级使用。每个属性的类型由编译器推断

通过关键词var可以接收一个匿名类型,实际上并不出来这种类型,它不会是编译器提供的一个障眼法,本质是,编辑器帮忙从后面的赋值语句推荐了类型。

使用匿名类型

这里构建了多种形式的匿名类型使用案例,它们都用过var来进行接收。

private void Form1_OrderCompleted(object sender, EventArgs e)
{
    var v = new { Amount = 108, Message = "Hello" };
    var x = 1;
    var y = 2;
    var order = new Order();
    var orderSum = (int x, int y) =>
    {
        Console.WriteLine(x + y);
    };
    orderSum.Invoke(x, y);
}

编译之后的样子。

.method private hidebysig 
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	// {
	IL_0000: nop
	// 	var anon = new
	// 	{
	// 		Amount = 108,
	// 		Message = "Hello"
	// 	};
	IL_0001: ldc.i4.s 108
	IL_0003: ldstr "Hello"
	IL_0008: newobj instance void class '<>f__AnonymousType0`2'<int32, string>::.ctor(!0, !1)
	IL_000d: stloc.0
	// int arg = 1;
	IL_000e: ldc.i4.1
	IL_000f: stloc.1
	// int arg2 = 2;
	IL_0010: ldc.i4.2
	IL_0011: stloc.2
	// Order order = new Order();
	IL_0012: newobj instance void demoForFormEvent31.Form1/Order::.ctor()
	IL_0017: stloc.3
	// 	Action<int, int> action = delegate(int x, int y)
	// 	{
	// 		Console.WriteLine(x + y);
	// 	};
	IL_0018: ldsfld class [mscorlib]System.Action`2<int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'
	IL_001d: dup
	IL_001e: brtrue.s IL_0037

	// (no C# code)
	IL_0020: pop
	// action(arg, arg2);
	IL_0021: ldsfld class demoForFormEvent31.Form1/'<>c' demoForFormEvent31.Form1/'<>c'::'<>9'
	IL_0026: ldftn instance void demoForFormEvent31.Form1/'<>c'::'<Form1_OrderCompleted>b__5_0'(int32, int32)
	IL_002c: newobj instance void class [mscorlib]System.Action`2<int32, int32>::.ctor(object, native int)
	IL_0031: dup
	IL_0032: stsfld class [mscorlib]System.Action`2<int32, int32> demoForFormEvent31.Form1/'<>c'::'<>9__5_0'

	IL_0037: stloc.s 4
	IL_0039: ldloc.s 4
	IL_003b: ldloc.1
	IL_003c: ldloc.2
	IL_003d: callvirt instance void class [mscorlib]System.Action`2<int32, int32>::Invoke(!0, !1)
	// }
	IL_0042: nop
	IL_0043: ret
} // end of method Form1::Form1_OrderCompleted

我们看到,var v = new { Amount = 108, Message = "Hello" };实际上是被创建了一个类型为AnonymousType的对象。

.class private auto ansi sealed beforefieldinit '<>f__AnonymousType0`2'<'<Amount>j__TPar', '<Message>j__TPar'>
	extends [mscorlib]System.Object
{
	.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
		01 00 00 00
	)
	.custom instance void [mscorlib]System.Diagnostics.DebuggerDisplayAttribute::.ctor(string) = (
		01 00 2b 5c 7b 20 41 6d 6f 75 6e 74 20 3d 20 7b
		41 6d 6f 75 6e 74 7d 2c 20 4d 65 73 73 61 67 65
		20 3d 20 7b 4d 65 73 73 61 67 65 7d 20 7d 01 00
		54 0e 04 54 79 70 65 10 3c 41 6e 6f 6e 79 6d 6f
		75 73 20 54 79 70 65 3e
	)
}

它基于System.Object的。

其他的,因为右侧都有明确的类型可以推断,所以编译器都编译为了具体的类型。

int arg = 1;
int arg2 = 2;
Order order = new Order();
Action<int, int> action = delegate(int x, int y)
{
	Console.WriteLine(x + y);
};

使用Linq查询表达式

LINQ查询表达式模式依赖于其所有功能的委托。

创建LINQ查询时,为此特定目的提供委托的实现。

public class Order
{
	public int Id { get; set; }
}

private void Form1_OrderCompleted(object sender, EventArgs e)
{
	var orders = new List<Order>();
	var smallNumbers = orders.Where(n => n.Id < 10);
}

编译后的结果

.method private hidebysig 
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	// {
	IL_0000: nop
	// List<Order> source = new List<Order>();
	IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<class demoForFormEvent31.Form1/Order>::.ctor()
	IL_0006: stloc.0
	// IEnumerable<Order> enumerable = source.Where((Order n) => n.Id < 10);
	IL_0007: ldloc.0
	IL_0008: ldsfld class [mscorlib]System.Func`2<class demoForFormEvent31.Form1/Order, bool> demoForFormEvent31.Form1/'<>c'::'<>9__6_0'
	IL_000d: dup
	IL_000e: brtrue.s IL_0027

	// }
	IL_0010: pop
	IL_0011: ldsfld class demoForFormEvent31.Form1/'<>c' demoForFormEvent31.Form1/'<>c'::'<>9'
	IL_0016: ldftn instance bool demoForFormEvent31.Form1/'<>c'::'<Form1_OrderCompleted>b__6_0'(class demoForFormEvent31.Form1/Order)
	IL_001c: newobj instance void class [mscorlib]System.Func`2<class demoForFormEvent31.Form1/Order, bool>::.ctor(object, native int)
	IL_0021: dup
	IL_0022: stsfld class [mscorlib]System.Func`2<class demoForFormEvent31.Form1/Order, bool> demoForFormEvent31.Form1/'<>c'::'<>9__6_0'

	IL_0027: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<class demoForFormEvent31.Form1/Order>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
	IL_002c: stloc.1
	IL_002d: ret
} // end of method Form1::Form1_OrderCompleted

它等价于

List<Order> source = new List<Order>();
IEnumerable<Order> enumerable = source.Where((Order n) => n.Id < 10);

处理NULL委托

在触发委托之前,我们最好先要确定下触发的这个委托是否为Null,一般使用?写成

private void Form1_OrderCompleted(object sender, EventArgs e)
{
    var orderOption = new OrderOption(InitOrderOption);
    orderOption?.Invoke();
}
.method private hidebysig 
	instance void Form1_OrderCompleted (
		object sender,
		class [mscorlib]System.EventArgs e
	) cil managed 
{
	// {
	IL_0000: nop
	// new OrderOption(InitOrderOption)?.Invoke();
	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
	// }
	IL_000e: ldloc.0
	IL_000f: brtrue.s IL_0013

	IL_0011: br.s IL_001a

	// (no C# code)
	IL_0013: ldloc.0
	IL_0014: callvirt instance void demoForFormEvent31.Form1/OrderOption::Invoke()
	IL_0019: nop

	IL_001a: ret
} // end of method Form1::Form1_OrderCompleted

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章