標籤:泛型 執行個體
以前我們為了能夠調用一個方法,必須比照這個方法定義一個相應的delegate.
原先我們定義delegate
// 委託聲明 -- 定義一個簽名:delegate doubleMathAction(double num);class DelegateTest{ // 符合委託聲明的常規方法 static double Double(double input) { return input * 2; } static void Main() { 原版: // 使用一個命名方法執行個體化委託類型 MathAction ma = Double; // 調用委託執行個體 double multByTwo = ma(4.5); Console.WriteLine(multByTwo); 簡化版1: // 再用匿名方法來執行個體化委託類型 MathAction ma2 = delegate(double input) { return input * input; }; double square = ma2(5); Console.WriteLine(square); 簡化版2: // 最後用Lambda運算式來執行個體化委託類型 MathAction ma3 = s => s * s * s; double cube = ma3(4.375); Console.WriteLine(cube); }}
這個是否能有更好的實現辦法呢?
答案是:肯定有了.也就是有通用的delegate了。在.NETFramework 3.5中,提供了兩類通用的delegate。
如果方法有返回值,則使用Func,或者Func<>
如果方法沒有返回值,則使用Action,或者Action<>
Func<T,TR>
T
此委託封裝的方法的參數類型。
TR
此委託封裝的方法的返回值類型。
在使用 Func<T,TResult>委託時,不必顯式定義一個封裝只有一個參數的方法的委託。以下樣本簡化了此代碼,它所用的方法是執行個體化 Func<T, TResult>委託,而不是顯式定義一個新委託並將命名方法分配給該委託。
使用Func<>委託,我們這樣寫
using System;public classLambdaExpression{ public static void Main() { Func<string, string> convert = s=> s.ToUpper();//該方法將小寫字母轉為大寫 string name = "Dakota"; Console.WriteLine(convert(name)); }}
Func委託是system下的全域函數,不用我們自定,系統自訂的,供我們使用,帶有多個重載.
這裡我們除了使用Func委託外,還是用了Labdab運算式.這裡我再談談這個運算式.
Lambda運算式的基礎類型是泛型 Func委託之一。 這樣能以參數形式傳遞 lambda運算式,而不用顯式將其分配給委託。 尤其是,因為 System.Linq命名空間中許多類型方法具有Func<T, TResult>參數,因此可以給這些方法傳遞 lambda運算式,而不用顯式執行個體化 Func<T, TResult>委託。
下面一行代碼將產生一個序列,其中包含 numbers 數組中在 9左側的所有元素,因為它是序列中第一個不滿足條件的數字:
int[] n= { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
執行個體2
var firstSmallNumbers =numbers.TakeWhile((n, index) => n >= index);
此樣本展示了如何通過將輸入參數括在括弧中來指定多個輸入參數。該方法將返回數字數組中的所有元素,直至遇到一個值小於其位置的數字為止。不要將 lambda運算子 (=>)與大於等於運算子 (>=)混淆。
三種委託寫法對比
using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace func{//委託聲明 -- 定義一個簽名:delegate double MathAction(double num);public class Program{// 符合委託聲明的常規方法static double Double(double input){return input * 2;} static void Main(string[] args){// 使用一個命名方法執行個體化委託類型/* * 寫法一,需要寫出專門委託的函數,還需要自訂委託 **/MathAction ma = Double;//注意這裡千萬不可有Double(),否則就成了一個傳回型別,是報錯的,這裡是制定函數的地址,給定的是函數的地址 //調用委託double result1 = ma(4.5); //使用系統自訂委託執行個體化委託類型/* * 寫法二,需要寫出專門委託的函數,不需要自訂委託,使用系統委託 **/Func<double,double> func = Double; //調用委託double result2 = func(4.5); //系統委託使用lamdba進行傳遞參數/* * 寫法三,不需要寫出專門委託的函數,還需要自訂委託 **/Func<double, double> result = s=> s * 2;//寫法還可以換成lamdba語句塊,適應多個參數的寫法 double result3=result(4.5); Func<double,double> result4 = s =>{return s * 2;}; Console.WriteLine(result1);Console.WriteLine(result3);Console.WriteLine(result2);Console.WriteLine(result4(4.5));} } }
同樣的輸出效果,但是編寫代碼的效果確實不同的。代碼的品質也是不同的。當然了也是要對自己的問題進行負責的。lamdba的使用簡化的代碼,但是如果自己不是對這個很熟悉,很容易造成出現問題,如從著手錯誤的源泉。匿名函數的寫法解決的這個問題。但是匿名函數卻沒有Lamdba簡便。這就是折中方法吧。看自己更喜歡哪種了。
小結:
從Func的委託中,我們可以看出,它簡化了我們自己定義委託帶來的繁瑣,同時它更好的結合了Lamdba的使用。減少了自訂函數的作用。同時也是有缺點的,就是錯誤的出現不容易發現是那裡。Action委託的使用與Func雷同,這裡就不在說了。希望自己的總結可以對大家有所協助。