C#中的代理与接口

时间:2012-01-01 19:17:18

标签: c# interface delegates

我想提出这个问题,只要我正在尝试深入研究代表的用途和目的,尽管很可能会以类似的方式提出这个问题。

我知道委托作为C ++中使用的函数指针。事实上,如果在C#中它们主要用作接口和多态的替代品。既然我可以创建特定类的子类并为它们提供适当的方法,那么除此之外还有什么代表呢?是否存在规定其使用的情况,或仅仅是代表使用时代码的可维护性得到改善?你会推荐他们在接口上的广泛部署吗?

我只是在谈论代表,我想区分他们的角色和事件角色。

5 个答案:

答案 0 :(得分:70)

是的,代表在很多方面都像单方法接口。但是:

  • CLR内置了支持
  • 在框架中支持它们,包括多播能力和异步调用
  • 以方法组转换,lambda表达式,匿名方法的形式提供额外的C#/ VB语言支持
  • 他们被要求举办活动(即活动和代表是一种配对)
  • 他们的意思是需要为您要创建的每个委托实例在单独的类中实现接口。

最后一点是最重要的一点 - 考虑LINQ表达式:

var query = collection.Where(x => x > 5)
                      .Select(x => x * x);

现在假设如果要表达x > 5x * x的逻辑,你必须为每个表达式编写一个单独的类,并实现一个接口:cruft与有用代码的数量将是荒谬的。当然,语言可以设计为允许通过单独的类从lambda表达式转换为接口实现,但是你仍然失去了能够简单地编写单独的方法并创建一个委托将其作为目标。你还会失去多播能力。

作为类似的思考练习,请考虑循环语句,例如whilefor。当我们goto时,我们真的需要吗?不。但生活要好得多 。代表们也是如此 - 实际上是属性,事件等。它们都使开发更简单。

答案 1 :(得分:28)

最大的实际区别在于,您可以为来自同一个类的同一个委托提供不同的委托实例,而不能使用接口。

void delegate XYZ(int p);

interface IXyz {
    void doit(int p);
}

class One {
    // All four methods below can be used to implement the XYZ delegate
    void XYZ1(int p) {...}
    void XYZ2(int p) {...}
    void XYZ3(int p) {...}
    void XYZ4(int p) {...}
}

class Two : IXyz {
    public void doit(int p) {
        // Only this method could be used to call an implementation through an interface
    }
}

答案 2 :(得分:16)

来自When to Use Delegates Instead of Interfaces (MSDN)

  

委托和接口都允许类设计器分离类型声明和实现。给定的接口可以由任何类或结构继承和实现。可以为任何类的方法创建委托,只要该方法适合委托的方法签名即可。接口引用或委托可以由不了解实现接口或委托方法的类的对象使用。鉴于这些相似之处,类设计者何时应该使用委托,何时应该使用接口?

     

在以下情况下使用代理:

     
      
  • 使用事件设计模式。
  •   
  • 希望封装静态方法。
  •   
  • 调用者无需访问实现该方法的对象上的其他属性,方法或接口。
  •   
  • 需要简单的组合。
  •   
  • 一个类可能需要多个方法的实现。
  •   
     

在以下情况下使用界面:

     
      
  • 可以调用一组相关的方法。
  •   
  • 一个类只需要一个方法实现。
  •   
  • 使用该接口的类将要将该接口强制转换为其他接口或类类型。
  •   
  • 正在实施的方法与类的类型或标识相关联:例如,比较方法。
  •   
     

使用单方法接口而不是委托的一个好例子是IComparable或通用版本IComparable(Of T)。 IComparable声明CompareTo方法,该方法返回一个整数,该整数指定小于,等于或大于相同类型的两个对象之间的关系。 IComparable可以用作排序算法的基础。虽然使用委托比较方法作为排序算法的基础是有效的,但它并不理想。由于比较能力属于类,比较算法在运行时不会改变,因此单方法接口是理想的。

来自Delegates Vs Interfaces in C#

  

代理和接口是C#中的两个不同概念,但它们具有共性。委托和接口都只包含声明。实现由不同的编程对象完成。

答案 3 :(得分:4)

委托和接口是C#中的两个不同概念。

接口允许扩展某些对象的功能,它是接口和实现它的对象之间的契约,而委托只是安全的回调,它们是一种函数指针。

答案 4 :(得分:1)

代表对接口的唯一真正优势是

  1. 代表甚至可以在.Net支持的泛型之前处理不同的参数类型。
  2. 一个类可以创建委托,公开共享相同签名的多个不同方法;用接口替换委托意味着每个类都可以暴露一个实现每个委托样式接口的方法而不创建辅助类,但是每个额外的实现都需要一个辅助类。

当.net不支持泛型时,委托是其中必不可少的一部分,因为为每个不同的函数签名声明不同的非泛型接口,但是想要通过这些接口是不可行的。如果.net从一开始就支持泛型,那么除了涉及Reflection的某些场景之外,代理是没有必要的,即使在那里,将Action<T,U>类型作为{{1}的实现也许是最有用的。 (所以代码只需要它可以IAction<T,U>的东西就可以使用接口)。在类需要创建暴露多个方法的委托的情况下,基于接口的方法需要创建单方法类,但是在许多常见情况下无需创建单独的委托实例,其中方法的数量很多。给出的签名恰好是一个。

顺便说一句,用接口替换委托绝不会阻止创建通用的Combine方法。实际上,界面协方差可以使这种方法在许多方面比现有的Invoke更好。实现类似于Delegate.Combine的方法充其量只是笨拙和讨厌,但我认为除了需要使用Delegate.Remove的事件订阅管理之外没有任何其他情况,并且事件订阅最好使用其他方法无论如何。