書接上回,在去年的
C# 委派(delegate) 介紹
這篇中了解到委派的使用方式,但是每次使用都要定義一個委派和一個委派實例,用起來有點麻煩,那有沒有更簡單的方式呢?
使用方式:
使用方式:
由上可知, delegate 和 Action 在使用的方式是一樣的,差別在於宣告方式。
補充: Action 空的實例化方式如下:
在 .NET 6 中可以簡化為:
使用方式:
使用方式:
再次補充:
上面委派使用時的程式碼可以省略 Invoke ,直接簡寫為:
但是在找不到委派實例的時候會拋出例外:
所以還是建議使用 ?.Invoke 的方式,在執行前先檢查是否為空。
參考資料:
Microsoft.Learn - Func<TResult> Delegate
Microsoft.Learn - Action<T> Delegate
Microsoft.Learn - Predicate<T> Delegate
StackOverflow - Is using Action.Invoke considered best practice?
原始 delegate 寫法
public class MyClass1
{
public delegate void OutputHandler(string output);
public OutputHandler? Output;
}
使用方式:
MyClass1 myClass1 = new MyClass1();
myClass1.Output += (output) =>
{
Console.WriteLine($"myClass1.Output: {output}");
};
myClass1.Output?.Invoke("Hello, World!");
Action
public class MyClass2
{
public Action<string>? Output;
}
使用方式:
MyClass2 myClass2 = new MyClass2();
myClass2.Output += (output) =>
{
Console.WriteLine($"myClass2.Output: {output}");
};
myClass2.Output?.Invoke("Hello, World!");
由上可知, delegate 和 Action 在使用的方式是一樣的,差別在於宣告方式。
補充: Action 空的實例化方式如下:
public Action<string>? Output = new Action<string>((str) => { });
在 .NET 6 中可以簡化為:
public Action<string>? Output = _ => { };
Func
Action 和 Func 的差異在於 Action 沒有回傳值,而 Func 有回傳值。Func 的最後一個參數就是回傳值的型態。宣告方式:
public class MyClass3
{
/// <summary>
/// 傳入 string,回傳 int
/// </summary>
public Func<string, int>? Output;
}
使用方式:
MyClass3 myClass3 = new MyClass3();
myClass3.Output += (output) =>
{
Console.WriteLine($"myClass3.Output: {output}");
return output.Length;
};
int? result = myClass3.Output?.Invoke("Hello, World!");
Console.WriteLine($"result: {result}");
/*
myClass3.Output: Hello, World!
result: 13
*/
Predicate
Predicate 可以理解為就是 Func ,只是回傳的參數類型固定是 bool
public class MyClass4
{
/// <summary>
/// 傳入 string,回傳 bool
/// </summary>
public Predicate<string>? Output;
}
使用方式:
MyClass4 myClass4 = new MyClass4();
myClass4.Output += (output) =>
{
if (string.IsNullOrWhiteSpace(output)) return false;
Console.WriteLine($"myClass4.Output: {output}");
return true;
};
bool? result = myClass4.Output?.Invoke("Hello, World!");
Console.WriteLine($"result: {result}");
/*
myClass4.Output: Hello, World!
result: True
*/
結論
其實 Action 、 Func 和 Predicate 都只是把最原始的 delegate 進行包裝,變成語法糖方便使用而已,在上篇學會 delegate 後就會發現這三個沒有什麼難的,反而是讓 delegate 的使用更加的方便。再次補充:
上面委派使用時的程式碼可以省略 Invoke ,直接簡寫為:
// Output?.Invoke("Hello, World!");
Output("Hello, World!");
但是在找不到委派實例的時候會拋出例外:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
所以還是建議使用 ?.Invoke 的方式,在執行前先檢查是否為空。
參考資料:
Microsoft.Learn - Func<TResult> Delegate
Microsoft.Learn - Action<T> Delegate
Microsoft.Learn - Predicate<T> Delegate
StackOverflow - Is using Action.Invoke considered best practice?
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com