使用嵌套泛型时,编译器在直接使用时会失败,但在使用约束时会正确编译。
示例:
public static void Test1<V, E>(this Dictionary<V, E> dict)
where V : IVertex
where E : IEdge<V>
{}
public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict){}
上面的两个扩展方法表面上具有相同的签名,但如果我现在尝试运行代码,例如:
var dict = new Dictionary<VertexInstance, EdgeInstance>();
dict.Test1();
dict.Test2();
编译器会在'Test2'上犯错,声明它无法转换为带有嵌入式嵌套泛型的泛型形式。我个人认为Test2
的语法更直观。
我最初发布这个问题是为了回答一个问题,该问题询问了使用通用约束和直接使用接口之间的区别,但我很好奇为什么会发生这种情况?
答案 0 :(得分:4)
扩展我的评论:
这些扩展方法当然没有相同的签名。 Dictionary<IVertex, IEdge<IVertex>>
与Dictionary<VertexInstance, EdgeInstance>
不同。 @Payo是对的;这是一个方差问题。类不能是共变或逆变的。接口可以,但只有当它们被标记出来时,IDictionary才能被标记为因为它不安全,所以更改为IDictionary在这里无济于事。
考虑是否允许这样做。您的Test2实现可能如下所示:
public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict)
{
dict.Add(new EvilVertex(), new EvilEdge());
}
EvilVertex和EvilEdge可以实现正确的接口,但不能从VertexInstance和EdgeInstance继承。然后调用将在运行时失败。因此,对Test2的调用不是安全的,因此编译器不允许它。
谢谢你的回答;但是,约束版本可能在内部具有相同的代码并且会有相同的问题,不是吗?
没有!约束版本不内部具有相同的代码,因为您无法从EvilVertex
转换为V
,也无法从EvilEdge
转换为E
。您可以 强制从类型强制转换为类型参数,首先强制转换为object
,但这在运行时会失败。
另外,为什么方差控制在那个水平?
因为泛型的一个目的是在编译时证明代码的类型安全性。
你的dict.Add应该有编译错误而不是我视图中的扩展方法。
如前所述,对dict Add 的调用是通用版本的编译器错误。 不能成为接口版本的编译器错误,因为在Test2的上下文中,您所知道的是您将EvilVertex转换为IVertex,这是完全合法的。