代表不只是速记界面吗?

时间:2020-03-06 14:23:03  来源:igfitidea点击:

假设我们有:

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中添加闭包(即匿名委托)的建议中,它们等效于具有单个成员方法的接口。