一提到委託,浮現在我們腦海中的大概是聽的最多的就是類似C++的函數指標吧,呵呵,至少我的第一個反應是這樣的。
關於委託的定義和使用,已經有諸多的人講解過,並且講解細緻入微,尤其是張子陽的那一篇。我就不用多廢話了。
今天我要說的是C#中的三種委託方式:Func委託,Action委託,Predicate委託以及這三種委託的常見使用情境。
Func,Action,Predicate全面解析
首先來說明Func委託,通過MSDN我們可以瞭解到,Func委託有如下的5種類型:
(1) *delegate TResult Func<TResult>();
(2)*delegate TResult Func<T1,TResult>(T1 arg1);
(3) *delegate TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2);
(4)*delegate TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3);
(5)*delegate TResult Func<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
其中(1)只能委託無參但是有傳回值的函數,TResult就是其傳回型別。
而(2)只能委託具有一個傳入參數,有傳回值的函數,T1為一個傳入參數,TResult為傳回型別。
(3)只能委託具有二個傳入參數,有傳回值的函數,T1和T2為兩個傳入參數,TResult為傳回型別,(4)和(5)以此類推。
那麼如何來使用呢? 下面給出一個簡單的幾個例子:
| 代碼如下 |
複製代碼 |
#region Func委託 ///Func<TResult>的用法 ///這裡TResult代表函數的傳回值類型 ///只能代理傳回值為TResult類型的無參函數 Func<string> func = delegate() { return "我是Func<TResult>委託出來的結果"; }; Console.WriteLine(func()); Console.ReadKey(); ///Func<T,TResult>的用法 ///這裡的T為代理的函數的傳入類型,TResult代表函數的傳回值類型 ///只能代理參數為T類型,傳回值為TResult類型的函數 Func<string, string> funcOne = delegate(string s) { return s.ToUpper(); }; Console.WriteLine(funcOne("我是Func<T,TResult>委託出來的結果")); Console.ReadKey(); ///Func<T1,T2,TResult>的用法 ///這裡T1,T2為代理的函數的傳入類型,TResult代表函數的傳回值類型 ///只能代理參數為T1,T2類型,傳回值為TResult類型的函數 Func<string, string, string> funcTwo = delegate(string value1, string value2) { return value1 + " " + value2; }; Console.WriteLine(funcTwo("我是", "Func<T1,T2,TResult>委託出來的結果")); Console.ReadKey(); #endregion
|
上面代碼中,我用了匿名方法來代替函數,其中delegate()代表無參函數,delegate(string s)代表有一個傳入參數的函數,以下的以此類推。
然後需要說明的就是Action委託,這個委託也是非常常用的,尤其是在涉及到線程和介面互動的時候,配合著lamada運算式使用,非常方便的實現二者的互動。後面我會提到用法。
來看看Action委託的幾種表現形式:
(1) * delegate void Action(); 無參,無傳回值
(2)* delegate void Action<T>(T1 arg1);
(3)* delegate void Action<T1,T2>(T1 arg1, T2 arg2);
(4)* delegate void Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);
(5)* delegate void Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
從上面可以看出,總共有5中表現形式,其中(1)既沒有傳入參數,也沒有傳回值,那麼它適合代理那些無參,無傳回值的函數;(2)有一個傳入參數,無傳回值,適合代理有參,無傳回值的函數,(3)(4)(5)以此類推。最都容納四個傳入參數。
那麼如何使用呢?下面有一些簡單的例子:
| 代碼如下 |
複製代碼 |
#region Action的用法 ///Action<T>的用法 ///這裡的T為代理函數的傳入類型,無傳回值 Action<string[]> action = delegate(string[] x) { var result = from p in x where p.Contains("s") select p; foreach (string s in result.ToList()) { Console.WriteLine(s); } }; string[] str={ "charlies","nancy","alex","jimmy","selina"}; action(str); Console.ReadKey(); #endregion
|
上面的例子是通過傳入的String類型的數組,找出其中包含有字元s的項,然後輸出到控制台。
最後一個就是Predicate委託,這個的形式比較少一些,就是一個傳入參數,傳回值為bool類型,具體樣本如下:
| 代碼如下 |
複製代碼 |
#region Predicate ///bool Predicate<T>的用法 ///輸入一個T類型的參數,傳回值為bool類型 Predicate<string[]> predicate = delegate(string[] x) { var result = from p in x where p.Contains("s") select p; if (result.ToList().Count > 0) { return true; } else { return false; } }; string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" }; if (predicate(_value)) { Console.WriteLine("They contain."); } else { Console.WriteLine("They don't contain."); } Console.ReadKey(); #endregion
|
上面的代碼其實也是判斷String數組中有沒有包含s的項,有的話就在控制台列印出 They contain.沒有的話就列印出They don't contain.
總結一下這三個的特點就是:
Func可以接受0個至4個傳入參數,必須具有傳回值
Action可以接受0個至4個傳入參數,無傳回值
Predicate只能接受一個傳入參數,傳回值為bool類型
| 代碼如下 |
複製代碼 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DelegateIntegrateConsoleApp { class Program { static void Main(string[] args) { #region Func委託 ///Func<TResult>的用法 ///這裡TResult代表函數的傳回值類型 ///只能代理傳回值為TResult類型的無參函數 Func<string> func = delegate() { return "我是Func<TResult>委託出來的結果"; }; Console.WriteLine(func()); Console.ReadKey(); ///Func<T,TResult>的用法 ///這裡的T為代理的函數的傳入類型,TResult代表函數的傳回值類型 ///只能代理參數為T類型,傳回值為TResult類型的函數 Func<string, string> funcOne = delegate(string s) { return s.ToUpper(); }; Console.WriteLine(funcOne("我是Func<T,TResult>委託出來的結果")); Console.ReadKey(); ///Func<T1,T2,TResult>的用法 ///這裡T1,T2為代理的函數的傳入類型,TResult代表函數的傳回值類型 ///只能代理參數為T1,T2類型,傳回值為TResult類型的函數 Func<string, string, string> funcTwo = delegate(string value1, string value2) { return value1 + " " + value2; }; Console.WriteLine(funcTwo("我是", "Func<T1,T2,TResult>委託出來的結果")); Console.ReadKey(); /*************餘下的類似上面的這種操作,最多可以接受四個傳入參數*************** *delegate TResult Func<TResult>(); *delegate TResult Func<T1,TResult>(T1 arg1); *delegate TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2); *delegate TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3); *delegate TResult Func<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4); */ #endregion #region Action的用法 ///Action<T>的用法 ///這裡的T為代理函數的傳入類型,無傳回值 Action<string[]> action = delegate(string[] x) { var result = from p in x where p.Contains("s") select p; foreach (string s in result.ToList()) { Console.WriteLine(s); } }; string[] str={ "charlies","nancy","alex","jimmy","selina"}; action(str); Console.ReadKey(); /***************餘下的類似上面的這種操作,最多可以接受四個傳入參數********** * delegate void Action(); 無參,無傳回值 * delegate void Action<T>(T1 arg1); * delegate void Action<T1,T2>(T1 arg1, T2 arg2); * delegate void Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3); * delegate void Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4); */ #endregion #region Predicate ///bool Predicate<T>的用法 ///輸入一個T類型的參數,傳回值為bool類型 Predicate<string[]> predicate = delegate(string[] x) { var result = from p in x where p.Contains("s") select p; if (result.ToList().Count > 0) { return true; } else { return false; } }; string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" }; if (predicate(_value)) { Console.WriteLine("They contain."); } else { Console.WriteLine("They don't contain."); } Console.ReadKey(); #endregion } } } |