public delegate void Action()
Action<T>:Action的泛型實現了1到16個傳入參數的定義,但是仍然沒有返回值,得出結論Action不支持返回值,如果需要返回值請使用另一個系統委托Func
public delegate void Action<in T>(T obj) ... public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>( T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16 )
由此可見Action的定義非常簡單,但是這樣的委托實在是太常用了,如果用一次自己定義一個也是可以的,多的話就感覺重復勞動太多:
過去自定義委托:

using System; using System.Windows.Forms; public delegate void ShowValue(); public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName); } } public class testTestDelegate { public static void Main() { Name testName = new Name("Koani"); ShowValue showMethod = testName.DisplayToWindow; showMethod(); } }
現在直接使用Action:

using System; using System.Windows.Forms; public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName); } } public class testTestDelegate { public static void Main() { Name testName = new Name("Koani"); Action showMethod = testName.DisplayToWindow; //將 Action 委托與匿名方法一起使用 // Action showMethod = delegate() { testName.DisplayToWindow();} ; //將 lambda 表達式分配給 Action 委托實例 //Action showMethod = () => testName.DisplayToWindow(); showMethod(); } }
Action<T>的使用也是類似的,但是 Action<T>的定義是比較特別的,它有一個關鍵詞In,In是用來干嘛的呢,按照MSDN的解釋:
關於派生程度更小或更低的類型等相關的概念理解我推薦深入理解 C# 協變和逆變
Func:封裝一個不具有參數但卻返回 TResult 參數指定的類型值的方法
public delegate TResult Func<out TResult>()
Func<T>: Func的泛型同樣的實現了1到16個傳入參數,而且支持返回值。
public delegate TResult Func<in T, out TResult>( T arg ) ... public delegate void Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16 )
Func的定義同樣簡單明了,和Action一樣是為了簡化代碼方便”客戶“使用:
過去自定義委托:

using System; using System.IO; delegate bool WriteMethod(); public class TestDelegate { public static void Main() { OutputTarget output = new OutputTarget(); WriteMethod methodCall = output.SendToFile; if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget { public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } } }
現在直接使用Func:

using System; using System.IO; public class TestDelegate { public static void Main() { OutputTarget output = new OutputTarget(); Func<bool> methodCall = output.SendToFile; //Func<bool> methodCall = delegate() { return output.SendToFile(); };將 Func<TResult> 委托與匿名方法一起使用 // Func<bool> methodCall = () => output.SendToFile(); 將 lambda 表達式分配給 Func<T, TResult> 委托 if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget { public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } } }
通過定義可以看到Func的定義不僅可以看到In關鍵詞的身影,還有一個Out關鍵詞,MSDN的解釋如下(Out作為方法的輸出參數也是經常用到的):
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace CLR { public class Employee { } class Program { static void Main(string[] args) { Employee emp = new Employee(); object obj = emp; IList<Employee> emplist = new List<Employee>(); // List<object> objlist = emplist; IList<object> objlist1 = emplist.Select(o => (object)o).ToList(); ; //因為Ilist的泛型參數T沒有使用Out關鍵詞標識,所以在給方法Add1直接傳遞 IList<Employee>類型的參數時會有無效參數提示 Add1(emplist); //間接的使用方法是像上面那樣逐個轉換 Add1(objlist1); IEnumerable<Employee> empenum = new List<Employee>(); IEnumerable<object> objenum = empenum; Add(empenum); Add(objenum); Console.ReadKey(); } private static void Add(IEnumerable<object> enums) { } private static void Add1(IList<object> enums) { } } }
關於派生程度更大或更高的類型等相關的概念理解我依然推薦深入理解 C# 協變和逆變