c# 常见委托有 delegate,Action,Func,Predicate。那它们有什么区别和联系呢?

1. Func , Action , Predicate 区别

定义

查看源码可以发现:

  1. Action , Func , Predicate 都是系统使用 delegate 定义的泛型委托。

  2. 它们具有不同的参数和返回值。

  3. 使用 in,out 定义了逆变和协变

public delegate void Action<in T>(T obj);
public delegate TResult Func<in T, out TResult>(T arg);
public delegate bool Predicate<in T>(T obj);

根据源码可以判断:

  1. 我们可以使用 delegate 代替 Action , Func , Predicate 这三种委托。

  2. 我们也可以使用类似的方法定义自己的委托。

根据委托的名字也可以判断大致的使用场景:

  1. Action 代表动作,代表执行一项操作,所以不具有返回值。

  2. Func 代表普通的函数,有参数和返回值。

  3. Predicate 断言,常用于判断数据是否符合要求。

参数和返回值区别:

  1. Func 至少 0 个参数,至多 16 个参数,必须有返回值,不能为 void 。

       public int Test<T1,T2>(Func<T1,T2,int>func,T1 a,T2 b)
       {
           return func(a, b);
       }
    
  2. Action 至少 0 个参数,至多 16 个参数,无返回值。

       public void Test<T>(Action<T> action,T p)
       {
           action(p);
       }
    
  3. Predicate 有且只有一个参数,返回值必须为 bool 。

       public bool Test<T>(Predicate<T> predicate,T p)
       {
           return predicate(p);
       }
    

2. delegate、Delegate、MulticastDelegate区别

委托继承的层次关系

System.Object  
=> System.Delegate    
==> System.MulticastDelegate
===> 使用 delegate 关键字自定义的委托

继承层次来源

前 3 层(Object,Delegate,MultiDelegate)来源于文档。
delegate继承是根据代码编译后生成的中间语言得出。

使用 ildasm.exe 可以看到,编译器将 delegate 编译为继承MulticastDelegate 的类

public delegate void BinaryOp(int x);

图1: 编译器生成的中间语言

区别

Delegate

Delegate 是一个委托的基类。定义了一些委托的基础方法。

MulticastDelegate

MulticastDelegate 继承Delegate ,并对其进行了一些扩展。

delegate

我们不能直接继承 DelegateMulticastDelegate。只有系统和编译器可以继承它们。
我们需要使用 delegate 关键字来定义委托,编译器会自动将委托编译为一个继承 MulticastDelegate 的类,并添加 BeginInvoke,EndInvoke,Invoke 等方法。例如上图图1

总结

  1. Action,Func,Predicate 都是系统使用 delegate 定义的委托。

  2. 使用delegate定义的委托 其实是继承MulticastDelegate的类(这也是为什么使用委托要先 new的原因:BinaryOp a = new BinaryOp(o=>{});)。

本文讲解的几种常用委托的区别。如有错误或遗漏之处,请在评论中指出。谢谢。

参考文章:

  1. c# 委托的介绍

  2. 委托(C# 编程指南)

  3. Delegate Class

  4. System.Delegate 和 delegate 关键字


meteor199
319 声望4 粉丝

下一篇 »
动态加载 js