为什么要使用或定义Action<T>和Predicate<T>作为委托?

4

请问有人能够解释在C#中使用Action<T>Predicate<T>委托的确切原因是什么?


1
请查看此问题 => https://dev59.com/63RC5IYBdhLWcg3wOeSB - Ashley Grenon
@Wondering,我不理解你问题的本质。你是在问为什么要使用其中一个而不是另一个吗? - Kirk Woll
我的意思是为什么它们是委托。 - Wondering
为什么不在问题中添加 Func<T> 呢? - Oded
3
你认为将它们设定为其他类型更有意义吗? - Matti Virkkunen
2
你可能不是有意的,但现在你的问题看起来像是:“为什么字符串由字符组成?”。所以请尝试更好地表达。 - H H
5个回答

11

你是在问它们存在的原因,还是在问它们为什么被定义为委托?

至于它们存在的原因,可能最好的原因就是方便。如果你想要一个返回无值并且参数为某种类型的委托,那么你可以自己定义:

public delegate void MyDelegate(int size);

然后稍后创建一个:

MyDelegate proc = new MyDelegate((s) => { // do stuff here });

当然,你需要针对每种不同的类型编写这样的方法。

或者,你可以使用Action<T>

Action<int> proc = new Action<int>((s) => { /* do stuff here */ });

当然,你可以简化为:

Action<int> proc = (s) => { /* do stuff here */ });

为什么它们是委托?因为这是在.NET中操作函数引用的方式:我们使用委托。注意上面例子中的相似之处。也就是说,MyDelegate 在概念上与 Action<int> 相同。虽然它们不是完全相同的东西,因为它们具有不同的类型,但是你可以轻松地将程序中每个 MyDelegate 的实例替换为 Action<int>,并且程序将正常工作。


4

它们还能是什么呢?委托是最灵活、最接近Action<T>Predicate<T>Func<T>所建模的内容 - 具有指定参数类型(也称为委托)的调用列表。


3
使用 Action<T>Predicate<T> 委托来执行操作和谓词操作的习语之所以被选择,最好的解释是先考虑替代方案。如果没有委托,你如何完成同样的事情?下一个最好的方案是使用接口 IActionIPredicate 并强制开发人员声明一个类并为每个不同类型的需要操作实现适当的接口。但是,这种方法的问题在于它需要更多的努力、更多的类扩散和不太可维护的代码。委托方法更加方便,因为您可以使用匿名方法或 lambda 表达式将逻辑与其将被使用的地方写在一起。

委托之所以方便,是因为编译器会自动生成与其相关的大量代码。从概念上讲,我不认为接口IAction<T>不能有一个属性,使得当编译器看到将方法组分配给IAction<Fnord>时,它将检查IAction<Fnord>是否包含一个符合消息组的签名的Invoke方法,并且如果是这样,生成一个类来实现IAction<Fnord>.Invoke作为对适当方法的调用。 - supercat
@supercat:是的,我想这是可能的。在C#中,将接口作为一等公民进行处理是有先例的...例如IDisposable。如果枚举器也实现了IDisposable,则foreach结构将调用Disposeyield关键字和IEnumerator的交互是另一个例子。我相信还有更多。所以,是的,你提出的建议几乎肯定是可行的。 - Brian Gideon
有时候,接口比委托更有效率,而有时候委托更有效率。就我个人而言,我希望每个委托都包含并实现了一个IInvoke接口(所以对于Action<Fnord,Woozle>,接口将是Action<Fnord,Woozle>.IInvoke);如果代码在实际使用时使用接口类型,那么这将提供最佳的解决方案。顺便说一句,我认为在委托类型中包含“BeginInvoke”很奇怪;我认为包含一个Bind方法会更有帮助... - supercat
将带有参数的委托以及这些参数的值转换为MethodInvoker。例如,如果Act是一个Action<int, string>,那么Act.Bind(5,"Hello")将生成一个MethodInvoker,该MethodInvoker将调用Act(5,"Hello")。据我所知,BeginInvoke必须将委托及其参数绑定到单个对象中,然后将该对象放置在线程池中;而不是将此类参数绑定功能绑定到线程池中,应将其单独公开。除其他外,这将允许像Control.BeginInvoke这样的东西具有类型安全性。 - supercat

2
因为它们是委托。

1
你只是在提出问题。 - Gabe

1

你从错误的角度看待这个问题。

问题不应该是“为什么需要 Action<>Func<>Predicate<> 委托?”(答案是“因为它们需要”)

真正的问题是,“为什么我们需要特定命名的对象来处理简单的委托任务?在可以使用普通委托的地方为什么要使用 Action<>?”

答案是,这些特定的委托在 CLR 本身上经常被使用,由于它们在 CLR 方法中被使用,最终开发人员将必须定义被调用的方法,委托的声明必须是公共的。因此,Microsoft 可以定义成千上万个委托,每个委托只用于一个 CLR 方法,或者定义一种简单的方式来指定需要哪种类型的委托。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接