多个泛型模糊

时间:2011-12-27 18:02:13

标签: c# .net vb.net generics generic-variance

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

  

接口'System.IObserver(Of Foo)'与另一个不明确   由于'In'和'实现了接口'System.IObserver(Of Bar)'   '接口IObserver(Of In T)'中的'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<Foo>, IObserver<Bar> {
        #region IObserver<Foo> 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<Bar> Members


        public void OnNext(Bar value) {
            throw new NotImplementedException();
        }

        #endregion
    }

2 个答案:

答案 0 :(得分:4)

总结:

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

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

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

答案 1 :(得分:3)

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

class Beholder
{
  public IObserver<Foo> FooObserver{get;private set;}
  public IObserver<Bar> BarObserver{get;private set;}
}

何时反对方差不明确?

我仍然没有看到立即出现问题,因此VB.net警告对我来说确实很奇怪。

IObserver<in T>是反变体。因此,为了引起歧义,您需要找到T这样的IObserver<Foo>IObserver<Bar> IObserver<T>。{/ p>

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

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

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

何时协方差模糊不清?

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

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