溫故知新,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

參考

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