# 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)