多个generics模糊

下面的代码是完全相同的,除了一个是C#,另一个是VB.Net。 C#编译得很好,但VB.Net会抛出警告:

接口’System.IObserver(Of Foo)’与另一个实现的接口’System.IObserver(Of Bar)’不明确,因为’接口IObserver(Of T)中的’In’和’Out’参数

为什么VB.Net显示警告而不是C#? 最重要的是,我该如何解决这个问题?

Obs:我正在使用.Net Framework 4和Visual Studio 2010 Ultimate。

VB.Net代码:

Module Module1 Sub Main() End Sub Public Class Foo End Class Public Class Bar End Class Public Class Beholder Implements IObserver(Of Foo) Implements IObserver(Of Bar) #Region "Impl" Public Sub OnCompleted() Implements System.IObserver(Of Bar).OnCompleted End Sub Public Sub OnError([error] As System.Exception) Implements System.IObserver(Of Bar).OnError End Sub Public Sub OnNext(value As Bar) Implements System.IObserver(Of Bar).OnNext End Sub Public Sub OnCompleted1() Implements System.IObserver(Of Foo).OnCompleted End Sub Public Sub OnError1([error] As System.Exception) Implements System.IObserver(Of Foo).OnError End Sub Public Sub OnNext1(value As Foo) Implements System.IObserver(Of Foo).OnNext End Sub #End Region End Class End Module 

C#代码:

  class Program { static void Main(string[] args) { } } public class Foo { } public class Bar { } public class Beholder : IObserver, IObserver { #region IObserver Members public void OnCompleted() { throw new NotImplementedException(); } public void OnError(Exception error) { throw new NotImplementedException(); } public void OnNext(Foo value) { throw new NotImplementedException(); } #endregion #region IObserver Members public void OnNext(Bar value) { throw new NotImplementedException(); } #endregion } 

加起来:

  • VB似乎在这里不必要地发出警告。 当他们从圣诞节假期回来时,我会向VB测试者提及它。
  • 这是一种可疑的编程实践,无论它是否安全; 实现同一接口的两个版本有点奇怪。
  • 如果您选择了像IEnumerable这样的协变接口,那么警告就是合理的。 如果你的对象既是海龟的序列又是长颈鹿的序列,那么当你隐式将它转换为动物序列时会发生什么? 你有海龟还是长颈鹿? 运行时只选择一个,这不一定是你想要的行为。

关于最后一点的一些有趣的讨论,请参阅我在2007年关于这个主题的文章的评论:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/09/covariance-and-contravariance-in-c-part-ten-dealing-with-ambiguity.aspx

实现两者都是糟糕的设计。 有两个不同的子对象,您订阅了两个观察者。 我建议有两个子对象,每个对象实现一个接口。

 class Beholder { public IObserver FooObserver{get;private set;} public IObserver BarObserver{get;private set;} } 

什么时候反差是模糊的?

我仍然没有看到一个直接问题,所以VB.net警告对我来说确实很奇怪。

IObserver是反变体。 因此,为了引起歧义,您需要找到一个T这样IObserverIObserver都是IObserver

如果FooBar都是独立类,则不存在这样的T ,因为它需要从它们两者派生,而.net类型系统不允许。

如果它们中的任何一个是接口,就会产生歧义:只需创建一个派生自Foo并实现IBar

如果一个派生自另一个,它也是不明确的:如果Foo派生自Bar ,那么IObserver也是IObserver

何时共变方式不明确?

最后使用共同变量接口,例如IEnumerable它足以拥有一个公共基类,两者都是引用可转换的。 并且Object为任何两个类(但不是值类型)实现了这一点。

IEnumerable在没有协方差的情况下会收支平衡,因为您需要非通用IEnumerable的一致实现,而这对于两个独立的类是不可能的。