首先,委托是一種類型,由關鍵字delegate聲明。確切的說,委托是一種可用於封裝命名或者匿名方法的引用類型。 它類似於 C++ 中的函數指針,而且是類型安全和可靠的。
委托類型的聲明與方法簽名相似,有一個返回值和任意數目任意類型的參數。 必須使用具有兼容返回類型和輸入參數的方法或 lambda 表達式實例化委托。下面給出了委托聲明及實例化的示例代碼:
1 // 委托聲明 -- 定義一個簽名: 2 delegate double MathAction(double num); 3 4 class DelegateTest 5 { 6 // 符合委托聲明的常規方法 7 static double Double(double input) 8 { 9 return input * 2; 10 } 11 12 static void Main() 13 { 14 // 使用一個命名方法實例化委托類型 15 MathAction ma = Double; 16 17 // 調用委托實例 18 double multByTwo = ma(4.5); 19 Console.WriteLine(multByTwo); 20 21 // 再用匿名方法來實例化委托類型 22 MathAction ma2 = delegate(double input) 23 { 24 return input * input; 25 }; 26 27 double square = ma2(5); 28 Console.WriteLine(square); 29 30 // 最后用Lambda表達式來實例化委托類型 31 MathAction ma3 = s => s * s * s; 32 double cube = ma3(4.375); 33 34 Console.WriteLine(cube); 35 } 36 }
以上給出了一般情況下委托的使用,那么接下來我想繼續了解Func<T, TResult>與委托的關系,還是直接從示例代碼入手,請往下看代碼:
1 using System; 2 3 delegate string ConvertMethod(string inString); 4 5 public class DelegateExample 6 { 7 public static void Main() 8 { 9 // 用命名方法來實例化委托類型 10 ConvertMethod convertMeth = UppercaseString; 11 string name = "Dakota"; 12 // 通過實例化后的委托實例去調用該方法 13 Console.WriteLine(convertMeth(name)); 14 } 15 16 private static string UppercaseString(string inputString) 17 { 18 return inputString.ToUpper(); 19 } 20 }
在使用 Func<T, TResult> 委托時,不必顯式定義一個封裝只有一個參數的方法的委托。以下示例簡化了此代碼,它所用的方法是實例化 Func<T, TResult> 委托,而不是顯式定義一個新委托並將命名方法分配給該委托。
1 using System; 2 3 public class GenericFunc 4 { 5 public static void Main() 6 { 7 // 依舊是用命名方法實例化委托類型 8 Func<string, string> convertMethod = UppercaseString; 9 string name = "Dakota"; 10 // 依舊是通過委托實例調用該方法 11 Console.WriteLine(convertMethod(name)); 12 } 13 14 private static string UppercaseString(string inputString) 15 { 16 return inputString.ToUpper(); 17 } 18 }
您也可以按照以下示例所演示的那樣在 C# 中將 Func<T, TResult> 委托與匿名方法一起使用。
1 using System; 2 3 public class Anonymous 4 { 5 public static void Main() 6 { 7 Func<string, string> convert = delegate(string s) 8 { return s.ToUpper();}; 9 10 string name = "Dakota"; 11 Console.WriteLine(convert(name)); 12 } 13 }
您還可以按照以下示例所演示的那樣將 lambda 表達式分配給 Func<T, TResult> 委托。
1 using System; 2 3 public class LambdaExpression 4 { 5 public static void Main() 6 { 7 Func<string, string> convert = s => s.ToUpper(); 8 9 string name = "Dakota"; 10 Console.WriteLine(convert(name)); 11 } 12 }
Lambda 表達式的基礎類型是泛型 Func 委托之一。 這樣能以參數形式傳遞 lambda 表達式,而不用顯式將其分配給委托。 尤其是,因為 System.Linq 命名空間中許多類型方法具有 Func<T, TResult> 參數,因此可以給這些方法傳遞 lambda 表達式,而不用顯式實例化 Func<T, TResult> 委托。
如果前面的解析看的不是很清楚,相信最后這個實例能夠讓你更加明白Func委托是多么有意思。
下面的示例演示如何聲明和使用 Func<T, TResult> 委托。 此示例聲明一個 Func<T, TResult> 變量,並為其分配了一個將字符串中的字符轉換為大寫的 lambda 表達式。 隨后將封裝此方法的委托傳遞給 Enumerable.Select 方法,以將字符串數組中的字符串更改為大寫。
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 6 static class Func 7 { 8 static void Main(string[] args) 9 { 10 // 聲明了一個Func委托類型的變量selector並用Lambda表達式進行實例化 11 // 這個Lambda表達式將用來獲取一個字符串並將這個字符串轉化為大寫並返回 12 Func<string, string> selector = str => str.ToUpper(); 13 14 // 創建一個字符串數組 15 string[] words = { "orange", "apple", "Article", "elephant" }; 16 // 依次遍歷這個字符串數組並調用委托實例selector進行處理 17 IEnumerable<String> aWords = words.Select(selector); 18 19 // 輸出結果到控制台 20 foreach (String word in aWords) 21 Console.WriteLine(word); 22 } 23 } 24 /* 25 This code example produces the following output: 26 27 ORANGE 28 APPLE 29 ARTICLE 30 ELEPHANT 31 */
通過委托和Lambda表達式及Func<>特性的結合,可以看出他們帶給代碼多么大的改變,不僅讓我們的代碼更加簡潔,更讓我們的代碼執行起來更加高效靈活。個人希望通過對委托的一些整理,加深對委托的理解和運用!