首先,委托是一种类型,由关键字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<>特性的结合,可以看出他们带给代码多么大的改变,不仅让我们的代码更加简洁,更让我们的代码执行起来更加高效灵活。个人希望通过对委托的一些整理,加深对委托的理解和运用!