c# 常见委托有 delegate,Action,Func,Predicate。那它们有什么区别和联系呢?
1. Func , Action , Predicate 区别
定义
查看源码可以发现:
Action , Func , Predicate 都是系统使用 delegate 定义的泛型委托。
它们具有不同的参数和返回值。
使用 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);
根据源码可以判断:
我们可以使用 delegate 代替 Action , Func , Predicate 这三种委托。
我们也可以使用类似的方法定义自己的委托。
根据委托的名字也可以判断大致的使用场景:
Action 代表动作,代表执行一项操作,所以不具有返回值。
Func 代表普通的函数,有参数和返回值。
Predicate 断言,常用于判断数据是否符合要求。
参数和返回值区别:
-
Func 至少 0 个参数,至多 16 个参数,必须有返回值,不能为 void 。
public int Test<T1,T2>(Func<T1,T2,int>func,T1 a,T2 b) { return func(a, b); }
-
Action 至少 0 个参数,至多 16 个参数,无返回值。
public void Test<T>(Action<T> action,T p) { action(p); }
-
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);
区别
Delegate
Delegate
是一个委托的基类。定义了一些委托的基础方法。
MulticastDelegate
MulticastDelegate
继承Delegate
,并对其进行了一些扩展。
delegate
我们不能直接继承 Delegate
和 MulticastDelegate
。只有系统和编译器可以继承它们。
我们需要使用 delegate
关键字来定义委托,编译器会自动将委托编译为一个继承 MulticastDelegate
的类,并添加 BeginInvoke
,EndInvoke
,Invoke
等方法。例如上图图1
。
总结
Action
,Func
,Predicate
都是系统使用delegate
定义的委托。使用
delegate
定义的委托 其实是继承MulticastDelegate
的类(这也是为什么使用委托要先new
的原因:BinaryOp a = new BinaryOp(o=>{});
)。
本文讲解的几种常用委托的区别。如有错误或遗漏之处,请在评论中指出。谢谢。