代表不只是速记界面吗?
假设我们有:
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); }
现在,我们可以作为Foo代表在Bar和Baz周围折腾。
除了获得较短的代码外,委托的真正好处是什么?
解决方案
不,委托用于方法指针。然后,可以确保与委托关联的方法的签名正确。
同样,我们也无需知道类的结构。这样,我们可以使用已编写的方法传递给另一个类中的方法,并定义要实现的功能。
使用Find方法查看List <>类。现在,我们需要定义什么来确定某项是否匹配,而无需该类中包含的项实现IListFindable或者类似项。
我们可以将委托作为函数中的参数传递(从技术上来说,委托在编译时可以成为对象,但这不是重点)。我们可以(显然)将一个对象作为参数传递,但是随后我们将该类型的对象与该函数绑定为参数。使用委托,我们可以传递任何函数以在具有相同签名的代码中执行,无论它来自何处。
委托是一种类型化的方法指针。这可以为我们提供比接口更多的灵活性,因为我们可以利用协方差和协方差,并且可以修改对象状态(必须将this指针与基于接口的函子一起传递)。
另外,代表有很多不错的语法糖,使我们可以轻松地将它们组合在一起。
可以将委托视为方法的接口,该接口定义方法必须具有哪些参数和返回类型才能适合委托
是的,可以将委托视为一种方法的接口。
有一点细微的区别,委托可以访问定义了它们的类的成员变量。在C(不同于Java)中,所有内部类都被认为是静态的。因此,如果我们使用接口来管理回调,例如按钮的ActionListener。需要将实现的内部类(通过构造函数)传递给包含类的部分的引用,该内部类在回调期间可能需要与之交互。代表没有此限制,因此减少了实现回调所需的代码量。
较短,更简洁的代码也是值得的。
从软件工程的角度来看,我们是对的,代表与函数接口非常相似,因为它们为函数接口提供了原型。
它们也可以以相同的方式使用:与传递包含所需方法的整个类(而不是传递整个类)相比,我们可以仅传递一个委托。这样可以节省大量代码,并创建更具可读性的代码。
此外,随着lambda表达式的出现,现在也可以轻松地对其进行快速定义,这是一个巨大的好处。尽管可以使用C#快速构建类,但实际上这是一个巨大的难题。
将两者进行比较是一个有趣的概念。从用例和代码结构的角度来看,我以前从未考虑过这些想法有多相似。
从调用者的角度来看,委托与接口引用有很多共同点,而接口引用只有一个方法。
在第一个示例中,Baz和Bar是可以继承和实例化的类。在第二个示例中,Baz和Bar是方法。
我们不能将接口引用仅应用于与接口协定匹配的任何类。该类必须显式声明它支持该接口。
我们可以将委托引用应用于与签名匹配的任何方法。
我们不能在接口协定中包含静态方法。 (尽管我们可以将静态方法与扩展方法结合使用)。
我们可以使用委托引用来引用静态方法。
接口和委托是完全不同的两件事,尽管我理解为了易于理解而用类似接口的术语描述委托的诱惑……但是,不了解事实可能会导致混乱。
代表受到启发(部分)是由于C ++方法指针的黑色艺术不足以实现某些目的。一个经典的示例是实现消息传递或者事件处理机制。委托允许我们定义方法签名,而无需了解类的类型或者接口,我可以定义" void eventHandler(Event * e)"委托,并在实现该委托的任何类上调用它。
有关此经典问题的一些见解以及为什么希望代表参加,请先阅读此内容,然后再阅读此内容。
在至少一个向Java中添加闭包(即匿名委托)的建议中,它们等效于具有单个成员方法的接口。