最近本身在調試C#項目,發現常常能夠看到委託和lambda
表達式,各類花裏胡哨的寫法把我給整的雲裏霧裏的,因而本身特地花了一點功夫來整理關於delegate
的相關知識,方便本身往後查閱。數組
委託是.NET中的尋址方法,和C++的
函數指針
很像;可是委託是類型安全的類
,定義了返回類型和參數類型,也就是說委託一種用戶自定義的類型,和普通的類同樣;安全
delegate void IntMethodInvoker(int x); //定義委託IntMethodInvoker, 參數是int,返回類型void
咱們能夠把委託當作是一件事情,就是給方法名字和返回類型指定一個
別名
函數
從上面的例子能夠總結出聲明委託的模板以下:spa
delegate
+ 返回類型 + 委託類型名 + 參數列表實例化委託,而且須要對其進行初始化,這樣能夠相似地當作一個變量使用了,下面給出一個具體的例子來講明如何使用委託。指針
using System; namespace DelegateSamples{ delegate double DoubleOp(double x); // 聲明一個委託類型 class MathOperations { public static doube MultiplyByTwo(double value) return value * 2; public static double Square(double value) return value * value; } class Program { static void Main() { // 聲明一個委託數組,就像普通數組同樣 DoubleOp[] operations = {MathOperations.MultiplyByTwo, MathOperations.Square}; for(int i = 0; i < operations.length; i++) { Console.WriteLine("using operations[{0}]:", i); ProcessAndDisplayNumber(operations[i], 3.2); Console.WriteLine(); } } static void ProcessAndDisplayNumber(DoubleOp action, double value) { double res = action(value); // 調用action實際封裝的方法 Console.WrireLine("Value is {0}, result of operation is {1}", value, res); } }
在調用委託的時候,最後判斷委託是否爲
null
,否則可能會引發異常調試
Action<T>
委託表示引用一個void返回類型的方法,Action<T>
有不少種變體,Action<in T>
調用帶一個參數的方法,沒有泛型參數的Action類調用不帶參數的方法;
Func<T>
委託相似,表示引用帶返回類型的方法,Func<T>
也有不少變體,Func<Out TResult>
表示調用帶返回類型但沒有參數的方法,Func<in T, out TRsult>
調用一個帶參數的方法,以此類推;code
// 聲明一個返回double類型,而且帶一個double參數的委託 Func <double, double> operations = {MathOperations.MultiplyByTwo, MathOperations.Square}; // 注意這個方法和上面方法的不同,利用了Func類 static void ProcessAndDisplayNumber(Func <double, double> action, double value) { double res = action(value); // 調用action實際封裝的方法 Console.WrireLine("Value is {0}, result of operation is {1}", value, res); }
在以前的例子中,每一個委託都只含有一個方法調用,也就是說調用多少次委託就是調用多少次方法。orm
可是,一個委託也能夠包含多個方法,這種委託叫作
多播委託
,所以,這種委託必須返回void
,否則返回的數據是不對的ip
Action<double> operations = MathOperations.MultiplyByTwo; operations += MathOperations.Square; //這裏在給委託添加一個方法
對於多播委託的使用,調用方法鏈的順序並沒獲得正式定義,這要求咱們儘可能避免依賴特定順序調用方法的代碼;編譯器
從上面的例子能夠知道,多播委託是能夠識別+,+=,-,-=這些符號的,下面給出具體的示意:
在上面的例子中,委託所調用的方法,都是咱們本身預先寫好的,可是委託也可使用匿名方法,也就是將匿名方法用做委託的參數,這在實例化委託的會有一些不同的,具體以下面例子所示:
string name = ""; // Func<string, string>委託接受一個string參數,返回一個string,注意匿名方法的實現,delegate開頭 Func<string, string> anonDel = delegate(string param){ param += name; param += "just for test"; return param; };
使用匿名方法須要遵照的規則:
在C#3.0以後,lambda表達式代替了匿名方法,寫起來感受更舒服;
lambda表達式主要是用來替代匿名方法的,由於顯然委託知道他本身須要調用的是什麼方法,不須要聲明delegate
關鍵字,在參數和方法體之間插入=>
,表示「goes to",具體示例以下所示:
string name = ""; // Func<string, string>委託接受一個string參數,返回一個string,這裏使用lambda表達式 Func<string, string> anonDel = param => { param += name; param += "just for test"; return param; }; // 這樣的lambda表達式是否是很優雅,就是調試程序的時候會有點煩
爲了更好地使用lambda表達式,方便咱們本身寫代碼寫的花裏花哨的,就對其多作一點介紹:
若是隻有一個參數,就只須要寫出參數名字就行
Func<string, string> oneParam = s => String.Format("change to Upper {0}", s.ToUpper());
使用多個參數,就把參數用寫在()裏
Func<double, double, double> twoParams= (x, y) => x * y; // 返回x*y
在使用多個參數的時候,我以爲仍是在參數前面加上類型比較好,便於理解,例如(double x, double y) => x * y;
只有一條語句,方法裏面不須要{}和return,編譯器會自動添加一個隱式的return
Func<double, double, double> result = x, y => x * y;
含有多條語句,須要加上{}和return
string lastname = "Alex"; Func<string ,string> printName = name => { name += lastname; return String.Format("Being Upper: {0}",name); }