委托函数大集结——C# delegate/lambda/Action/Func/Predicate总结

C# 的委托类似于 C++ 的函数指针,将方法作为参数传递,但类型安全。
普通的委托需要经过声明类型、准备方法、实例化传入方法之后才能使用,流程比较繁琐。

public delegate void MyDelegate(string str); // 声明类型
public static void Hello(string name) // 准备方法
{ 
    Console.WriteLine("Hello " + name); 
} 
MyDelegate md = new MyDelegate(Hello); // 实例化传入方法
md("XiaoMing"); // 使用

// Output:
//
// Hello XiaoMing

因此产生了使用匿名方法表达式和 lambda 表达式简化的操作。
另外微软也在框架中预定义了三种委托函数 Action/Func/Predicate 进一步做了简化。
下面就简单总结下两种表达式和三种委托函数。

§1 匿名方法表达式和 lambda 表达式

先看下使用这两种表达式的简化效果,主要在于不需要准备方法,可以在实例化时直接传入。

public delegate void MyDelegate(string str);
static void Main(string[] args)
{
    // 匿名方法表达式
    MyDelegate md1 = delegate (string str) { Console.WriteLine("Hello " + str); };
    md1("XiaoMing");
    // lambda 表达式
    MyDelegate md2 = (str) => { Console.WriteLine("Hello " + str); };
    md2("XiaoMing");
}

1.1 两者的区别

通过以下例子说明两种表达式的区别,每一块第一行使用匿名方法表达式,第二行使用 lambda 表达式。虽然使用了还没介绍的 Func 委托和 Action 委托,但当前我们可以只关注 = 右边的部分。

// Comparison 1
Func sum1 = delegate (int a, int b) { return a + b; };
Func sum2 = (a, b) => { return a + b; };

// Comparison 2
Action introduce1 = delegate (int a, double b) { Console.WriteLine("This is world!"); };
Action introduce2 = (a, b) => { Console.WriteLine("This is world!"); };

// Comparison 3
Action introduce3 = delegate { Console.WriteLine("This is world!"); };
Action introduce4 = () => { Console.WriteLine("This is world!"); }; // 编译错误

可以看到使用 lambda 表达式的代码比使用匿名方法表达式更简洁。
而第三组中使用 lambda 表达式的编译会出错,因为参数与 Action 输入参数不符,但使用匿名方法表达式则无此问题。根据 MSDN 的文档可知:

That's the only functionality of anonymous methods that is not supported by lambda expressions. In all other cases, a lambda expression is a preferred way to write inline code.
这是lambda表达式不支持的匿名方法的唯一功能。在其他情况下,lambda表达式是编写内联代码的首选方法。

因此这里只讲一下 lambda 表达式。

1.2 lambda 表达式

(input parameters) => {statement;}
中间的 => 为 lambda 运算符,左边为输入参数,右边为表达式语句。
一般的表达式看起来是这样的(= 右边的部分):

Func isEqual = (int a, int b) => { return a == b; };
Func isEqual = (a, b) => { return a == b; }; // 简化
Func isEqual = (a, b) => a == b; // 再简化

Func isFive = (int a) => { return a == 5; };
Func isFive = (a) => { return a == 5; }; // 简化
Func isFive = a => a == 5; // 再简化

§2 Action 委托

封装有若干个参数且无返回值的方法,参数数量 0~16。

public delegate void Action();
public delegate void Action(T obj);
public delegate void Action(T1 arg1, T2 arg2);
public delegate void Action(T1 arg1, T2 arg2, T3 arg3);
......
public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

用以下示例说明 Action 委托的用法,示例程序使用了两个不同参数的 Action,作用均是向 types 中添加元素。

List types = new List();
// 传入参数类型为 int
Action add1 = (a) => types.Add(a.GetType());
// 传入参数类型为 float 和 double
Action add2 = (a, b) =>
{ 
    types.Add(a.GetType()); 
    types.Add(b.GetType()); 
};
add1(1);
add2(2f, 3.0);
types.ForEach((i) => Console.WriteLine(i));

// Output:
//
// System.Int32
// System.Single
// System.Double

§3 Func 委托

封装有若干个参数且有返回值的方法,参数数量 0~16。

public delegate TResult Func(T arg);
public delegate TResult Func(T1 arg1, T2 arg2);
public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3);
......
public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

用以下示例说明 Func 委托的用法,示例程序使用了三个不同参数的 Func。

// 无传入参数,返回类型为 string
Func getTypeString1 = () => { return "2020"; }; 
// 传入参数类型为 int,返回类型为 string
Func getTypeString2 = (a) => { return a.GetType().ToString(); };
// 传入参数类型为 float 和 double,返回类型为 string
Func getTypeString3 = (a, b) => 
{
    return a.GetType().ToString() + " " + b.GetType().ToString();
};
Console.WriteLine(getTypeString1());
Console.WriteLine(getTypeString2(1));
Console.WriteLine(getTypeString3(2f, 3.0));

// Output:
//
// 2020
// System.Int32
// System.Single System.Double

与 Action 委托的区别:Action 无返回值,Func 有返回值。

§4 Predicate 委托

封装一个参数且返回类型为 bool 的方法,常用于 ArrayList 的元素搜索方法。

public delegate bool Predicate(T obj);

与 Func 委托的关系:其实是返回类型为 bool 的 Func 委托的再次封装,与下面这句等价:

public delegate bool Func(T arg);

§5 总结

干就完了。

推荐阅读

  • delegate operator - C# reference | Microsoft Docs
  • Lambda expressions - C# Programming Guide | Microsoft Docs
  • Action Delegate (System) | Microsoft Docs
  • Func Delegate (System) | Microsoft Docs
  • Predicate Delegate (System) | Microsoft Docs

你可能感兴趣的:(委托函数大集结——C# delegate/lambda/Action/Func/Predicate总结)