# Delegate, Lambda expressions, IEnumerable (2/17) ###### tags: `Delegate` `delegate` `=>` `IEnumerable` `note` `ASP.NET` ## Delegate type\[2] - A delegate is a type that safely encapsulates a method. - Delegates allow methods and object to be passed as parameters. The following code example demonstrates how deledate safely encapsulates a method, and pass method as a parameter. ```csharp public delegate void MessageDelegate(string message); public static void MyPrint1(string msg) { Console.Write(msg); } public static void MyPrint2(int num) { Console.Write(num.ToString()); } ``` ```csharp // Instantiate the delegate. MessageDelegate Foo = MyPrint1; // Since parameter of MyPrint2 is int, causing a problem here. MessageDelegate Bar = MyPrint2; // Call the delegate. Foo("Ahoy!\n"); // Ahoy! MyPrint1("Hi-rys!\n"); // Hi-rys! ``` - Delegates can be chained together; for example, multiple methods can be called on a single event. ```csharp public delegate void MessageDelegate(string message); public static void MsgBeenAttacked(string name) { Console.Write($"{name} has been attcked!\n"); } public static void MsgDown(string name) { Console.Write($"{name} downed"); } ``` ```csharp MessageDelegate Msg_Attacked, Msg_Down, Msg_Multi; Msg_Attacked = MsgBeenAttacked; Msg_Down = MsgDown; Msg_Multi = Msg_Attacked + Msg_Down; Msg_Multi("Uruha Rushia"); /* Output: Uruha Rushia has been attcked! Uruha Rushia downed */ ``` Also, we can combine multiple methods like ```csharp MessageDelegate Msg_Multi; Msg_Multi = (MessageDelegate)MsgBeenAttacked + (MessageDelegate)MsgDown; Msg_Multi("Uruha Rushia"); /* Output: Uruha Rushia has been attcked! Uruha Rushia downed */ ``` ## "delegate" operator - The delegate operator **creates an anonymous method** that can be converted to a delegate type.\[3]\[4] ```csharp // Action can't return values Action<int, double> Calc_Prt = delegate(int a, double b) { Console.WriteLine(a+b); }; // Func<in1 T, in2 T, ..., out T> Func<int, double, double> Calc_Rtn = delegate(int a, double b) { return(a+b); }; // Predicate<in T> return bool, can have up to only one argument, // using object for multi inputs (such as tuple). Predicate<(int, double)> Equal3 = delegate((int att1, double att2) a) { return a.att1+a.att2==3.0; }; Console.WriteLine(Equal3((1, 2.0))); /* Note: Both "Func" and "Action" are sort of "Delegate" Class. */ ``` ## Lambda "expressions" - Use a lambda expression to create an anonymous function instead using delegate operator. Lambda expression 語法如下 ``` (input-parameters) => expression (input-parameters) => { <sequence-of-statements> } ``` Lambda expression 與 delegate operator 之比較如下 ```csharp Func<int, int, bool> Equal1 = delegate(int a, int b) { return a==b; }; Func<int, int, bool> Equal2 = (a, b) => a==b; Func<int, int, bool> Equal3 = (a, b) => { return a==b; }; ``` 可看到 => 較 delegate 簡潔且直觀許多,這項優點在使用LINQ下的類別與方法時特別明顯,下面以IEnumerable物件為例。 ```csharp // anonymous delegate List<int> evens_1 = Enumerable .Range(1, 100) .Where(delegate(int x) { return (x % 2) == 0; }) .ToList(); // delegate 在宣告 anonymous function 時一定要指定 input 的 DataType,且不管函式多簡單 { } 都無法省略。 // lambda expression List<int> evens_2 = Enumerable .Range(1, 100) .Where(x => (x % 2) == 0) .ToList(); ``` 上列程式碼的運作邏輯為: step 1:利用 Enumerable.Range() return 一個 IEnumerable 物件。 step 2:利用 step 1的 \<IEnum> 物件下的 Where(Func<..., Boolean>) 再 return 一個 IEnumerable 物件。 step 3:利用 step 2的 \<IEnum> 物件下的 ToList() 將 query 後的 \<IEnum> return 成一個 List\<int> assign to evens。 從上述找 1~100 偶數的例子便可看出,隨著Query的次數增加, delegate 的寫法會很醜,很多廢話。 ### 心得 1. 利用 Delegate type 來撰寫更嚴謹的程式碼,也可用於專案初期的程式方塊規劃。 2. IEnumerable / Enumerable 下面的很多Methods運作方式有點像遞迴(詞窮,沒有其他更貼切的比喻)。例如: \<IEnumerable>.Method() 又回傳一個 IEnumerable物件,就是用這種\<IEnumerable>.Method().Method().Method()...的方式去做Query。 ### 延伸關鍵字 or 還想不通怎麼運作的東西 1. Language Integrated Query (LINQ) 2. Enumerable下的Methods有哪些用法 ## 參考資料 \[1] 陳明山,江通儒,ASP.NET Core 打造 軟體積木和應用系統 \[2] [C# Ref - using Delegates](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates) \[3] [delegate-operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/delegate-operator) \[4] [Func vs. Action vs. Predicate](https://stackoverflow.com/questions/4317479/func-vs-action-vs-predicate) \[5] [C# Lambda expressions: Why should I use them?](https://stackoverflow.com/questions/167343/c-sharp-lambda-expressions-why-should-i-use-them)