多泛型歧义
本文关键字:歧义 泛型 | 更新日期: 2023-09-27 18:18:49
下面的代码是完全相同的,除了一个是c#,另一个是VB.Net。c#编译得很好,但是VB。Net抛出警告:
接口的系统。observer (Of Foo)'与另一个有歧义实现接口系统。IObserver(Of Bar)’,因为有"In"和'接口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
}
总结:
- 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两者同时实现是糟糕的设计。有两个不同的子对象,分别订阅两个观察者。我建议使用两个子对象,每个子对象实现一个接口。
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>
。
如果Foo
和Bar
都是独立的类,则不存在这样的T
,因为它需要从它们两个派生,这是。net类型系统不允许的。
如果它们中的任何一个是接口,就会产生歧义:只创建一个从Foo
派生并实现IBar
的类。
如果其中一个衍生自另一个,那么它也是不明确的:如果Foo
衍生自Bar
,那么IObserver<Bar>
也是IObserver<Foo>
。
协方差何时有歧义?
最后,对于协变接口,如IEnumerable<T>
,有一个公共基类就足够了,这两个基类都是可引用转换的。Object
为任意两个类(但不包括值类型)实现了这一点。
但是如果没有协方差,IEnumerable<T>
就会收支平衡,因为您需要非泛型IEnumerable
的一致实现,而这对于两个独立的类是不可能的。