下面的代码完全相同,只是一个是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
}
答案 0 :(得分:4)
总结:
IEnumerable<T>
,那么警告就是合理的。如果你的对象既是海龟的序列又是长颈鹿的序列,那么当你隐式将它转换为动物序列时会发生什么?你有海龟还是长颈鹿?运行时只选择一个,这不一定是你想要的行为。关于最后一点的一些有趣的讨论,请参阅我2007年关于这个主题的文章的评论:
答案 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>
如果Foo
和Bar
都是独立的类,则不存在这样的T
,因为它需要从它们两者派生,而.net类型系统不允许。
如果它们中的任何一个是界面,就会产生歧义:只需创建一个派生自Foo
并实现IBar
的类。
如果一个来自另一个,那么它也是不明确的:如果Foo
来自Bar
,那么IObserver<Bar>
也是IObserver<Foo>
。
最后使用共同变量接口,例如IEnumerable<T>
,它足以拥有一个公共基类,两者都是引用可转换的。并且Object
为任何两个类(但不是值类型)实现了这一点。
但是IEnumerable<T>
在没有协方差的情况下会收支平衡,因为你需要非泛型IEnumerable
的一致实现,而这对于两个独立的类是不可能的。