温故知新,CSharp遇见事件和委托(Event/Delegate),通过ILSpy反编译代码,透过现象看本质
事件和委托的区别到底是什么
委托提供了一种机制,可实现涉及组件间最小耦合度的软件设计,它是一种引用类型。
和委托类似,事件是后期绑定机制。事件是建立在对委托的语言支持之上的,它是对委托的封装,可以理解为一种特殊的委托(本质不是)。
事件是对象用于广播已发生事情的一种方式。任何其他组件都可以订阅事件,并在事件引发时得到通知。
相同点
- 它们都提供了一个后期绑定方案:在该方案中,组件通过调用仅在运行时识别的方法进行通信。
- 它们都支持单个和多个订阅服务器方法。这称为单播和多播支持。
- 二者均支持用于添加和删除处理程序的类似语法。
- 引发事件和调用委托使用完全相同的方法调用语法。它们甚至都支持与
?.
运算符一起使用的相同的Invoke()
方法语法。
不同点
- 用于事件的委托通常没有返回值,如果需要返回值,那么请使用委托。
- 对事件的侦听是可选的。
- 事件只能从外部添加和删除响应方法,不能主动触发事件、获取其它注册的响应方法,而委托不受这种限制。
揭秘事件
一探究竟
在控制台程序中定义一个事件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_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_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)
{
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2021-10-30 时光卷轴,前微软中国战略合作总监刘润老师,《进化的力量 · 年度演讲2021》,图文朗读版
2021-10-30 乘风破浪,遇见最美Windows 11之现代Windows开发运维 - VMware Player虚拟机安装Windows 10