扩展我的评论:
这些扩展方法当然没有相同的签名。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 的调用无法证明是安全的,因此编译器不允许这样做。
谢谢你的回答;但是,约束版本内部可能有相同的代码并且会有相同的问题,不是吗?
No! The constraints version could not have the same code inside, because you can't convert from EvilVertex
to V
, nor from EvilEdge
to E
. You could force a cast from the type to the type parameter, by casting first to object
, but that would of course fail at run time.
Also, why is variance controlled at that level?
Because one purpose of generics is to prove the code's type safety at compile time.
Your dict.Add should have the compilation error not the extension method in my view.
As mentioned, the call to dict Add is a compiler error for the generic version. It can't be a compiler error for the interface version, because in the context of Test2, all you know is that you're converting EvilVertex to IVertex, which is perfectly legal.