题
假设我们有:
interface Foo
{
bool Func(int x);
}
class Bar: Foo
{
bool Func(int x)
{
return (x>0);
}
}
class Baz: Foo
{
bool Func(int x)
{
return (x<0);
}
}
现在我们可以将 Bar 和 Baz 作为 Foos 来使用并调用它们的 Func 方法。
代表们对此进行了一些简化:
delegate bool Foo(int x);
bool Bar(int x)
{
return (x<0);
}
bool Baz(int x)
{
return (x>0);
}
现在我们可以将 Bar 和 Baz 作为 Foo 代表来折腾了。
除了获得更短的代码之外,委托的真正好处是什么?
解决方案
有一个细微的区别,委托可以访问定义它们的类的成员变量。在 C# 中(与 Java 不同),所有内部类都被认为是静态的。因此,如果您使用接口来管理回调,例如按钮的 ActionListener。实现内部类需要(通过构造函数)传递对包含类在回调期间可能需要与之交互的部分的引用。委托没有此限制,因此减少了实现回调所需的代码量。
更短、更简洁的代码也是一个有价值的好处。
其他提示
从软件工程的角度来看,你是对的,委托很像函数接口,因为它们是函数接口的原型。
它们也可以以同样的方式使用:您可以只传递一个委托,而不是传递包含您需要的方法的整个类。这节省了大量代码并创建了更具可读性的代码。
此外,随着 lambda 表达式的出现,它们现在也可以轻松地动态定义,这是一个巨大的好处。虽然可以用 C# 动态构建类,但这确实是一个巨大的痛苦。
比较两者是一个有趣的概念。我之前没有考虑过从用例和代码结构的角度来看这些想法有多么相似。
从调用者的角度来看,委托确实与具有单个方法的接口引用有很多共同点。
在第一个示例中,Baz和Bar是类,可以继承和实例化。在第二个示例中,Baz 和 Bar 是方法。
您不能将接口引用仅应用于与接口协定匹配的任何类。该类必须显式声明它支持该接口。您可以将委托引用应用于与签名匹配的任何方法。
您不能在接口的契约中包含静态方法。(尽管您可以将静态方法与扩展方法结合起来)。您可以使用委托引用来引用静态方法。
不,委托用于方法指针。然后您可以确保与委托关联的方法的签名是正确的。
另外,你不需要知道类的结构。这样,您可以使用您编写的方法传递到另一个类中的方法,并定义您想要实现的功能。
看看 具有 Find 方法的 List<> 类. 。现在,您可以定义确定某些内容是否匹配的因素,而不需要类中包含的项目来实现 IListFindable 或类似的内容。
您可以将委托作为函数中的参数传递(好吧,从技术上讲,委托在编译时会成为对象,但这不是这里的重点)。您可以将对象作为参数传递(显然),但随后您将该类型的对象作为参数绑定到函数。使用委托,您可以传递任何要在具有相同签名的代码中执行的函数,无论它来自何处。
人们可以将委托视为一种方法的接口,它定义了方法必须具有哪些参数和返回类型以适合委托
是的,委托可以被视为具有一种方法的接口。
委托是一个类型化方法指针。这为您提供了比接口更大的灵活性,因为您可以利用协变和逆变,并且可以修改对象状态(您必须使用基于接口的函子传递 this 指针)。
此外,Delegate 有很多很好的语法糖,可以让你轻松地将它们组合在一起。
在至少一项添加闭包的提案中(即匿名委托)对于 Java 来说,它们相当于具有单个成员方法的接口。