2019年8月27日 星期二

[.NET] Lambda 不能轉換為 System.Delegate Type

markdown C# 的 lambda 可以轉換為 delegate type,例如 Action 或 Func,你可以用下面的方式宣告一個 Func,並且用一個 lambda assign 給它。
Func<int, int> func = (x) => x * x;
但是無法用 lambda assign 給 [System.Delegate](https://docs.microsoft.com/zh-tw/dotnet/api/system.delegate?view=netframework-4.8) type,例如下面例子會 compile fail。
Delegate d = (x) => x * x; // Compile fail
這是因為 lambda 只能指定給 delegate type,例如 Action 或 Func,但是 System.Delegate 不是 delegate type,雖然它是所有 delegate type 的父類。這有點難理解,但 C# 就是這麼定義的。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnShkZ9D9YsusmB_GB8FY3OOLXcGqKb3q8-c6HOSBSOcoPJFee050naiEOtO108EdzrMcWUtyklh2H0X7F5nHGBCWIF6abTs5qUsS_ABfv1Bxu0d6PQxFu2BzMJvtUEIsFM_07dsW9wylr/s1600/Image+18.png) 甚麼時候會遇到這種情況呢?在你要用 Form 的 [Invoke](https://docs.microsoft.com/zh-tw/dotnet/api/system.windows.forms.control.invoke?view=netframework-4.8#System_Windows_Forms_Control_Invoke_System_Delegate_) 或 [BeginInvoke](https://docs.microsoft.com/zh-tw/dotnet/api/system.windows.forms.control.begininvoke?view=netframework-4.8#System_Windows_Forms_Control_BeginInvoke_System_Delegate_) 的時候,因為你可以看到,Invoke 跟 BeginInvoke 接受的是一個 System.Delegate 型別的參數,所以你不能直接用 lambda 當參數傳進去。
Form f = new Form();
f.Invoke((x) => x * x);  // Compile fail
解決的方法是用 Func 或 Action instance 當參數傳進去,因為 System.Delegate 是所有 Action 和 Func 這些 delegate type 的父類,所以可以接受 Action 或 Func。
Form f = new Form();
f.Invoke(new Action(() => Console.WriteLine("Test")));