Contravariance/Covariance,为什么不能投这个?
Contravariance/Covariance, why can't cast this?
面对现实吧,在泛型中使用协变和逆变时,我仍然难以理解约束。
我想知道,为什么我有这个:
public interface IFasterListCov<out T>
{}
public interface IFasterListCon<in T>
{}
public class FasterList<T> : IList<T>, IFasterListCov<T>, IFasterListCon<T>
第三次施法失败:
public void QueryNodes<T>() where T:INode
{
//somehow I can convert IFasterListCon<INode> to IFasterListCon<T>
IFasterListCon<INode> nodes = (IFasterListCon<INode>)_nodesDB[type];
//I guess this works because _nodesDB[type] is indeed a FasterList<T> object
//note: I am wrong, I can cast whatever INode implementation, not just T, which made me very confused :P
IFasterListCon<T> nodesT = (IFasterListCon<T>)nodes;
//I can't cast IFasterListCon<T> back to FasterList<T>
FasterList<T> nodeI = nodesT as FasterList<T>; //null
}
Dictionary<Type, IFasterListCov<INode>> _nodesDB;
to be clear _nodesDB[type] is a FasterList<T> declared through IFasterListCov<INode>
在您调用 QueryNodes<MyNode>
的情况下,为了让您的最后一次转换获得非空值,您使用 _nodesDB[type]
获得的实际实例必须是 FasterList<MyNode>
。 FasterList<SomeOtherMostlyCompatibleNode>
.
还不够好
运行时对类型非常严格,它跟踪所涉及的所有内容的实际运行时类型,数据类型相似或只有 MyNode
个对象填充是不够的您的 FasterList<SomeOtherMostlyCompatibleNode>
,或其他任何内容。如果类型不完全它们应该是什么,您需要进行某种编程转换,而不仅仅是转换。
MyType : IMyType
不会使 Generic<IMyType>
和 Generic<MyType>
有任何关联。
在您的特定情况下,nodesT
很可能是 FasterList<Node>
,而 不是 FasterList<INode>
.
请注意,当您可以指定 in
/out
时,此转换适用于支持变体 (co/contra) 的接口,正如您在成功转换为接口时看到的那样。有关详细信息,请参阅许多问题之一 - 即 Generic Class Covariance.
关于 List
协方差也有很好的答案 - C# variance problem: Assigning List<Derived> as List<Base> 这表明 List<Derived>
和 List<Base>
不能相互转换:
List<Giraffes> giraffes = new List<Giraffes>();
List<Animals> animals = new List<Animals>() {new Lion()};
(giraffes as List<Animals>).Add(new Lion()); // What? Lion added to Girafes
Giraffe g = (animals as List<Giraffes>)[0] ; // What? Lion here?
面对现实吧,在泛型中使用协变和逆变时,我仍然难以理解约束。
我想知道,为什么我有这个:
public interface IFasterListCov<out T>
{}
public interface IFasterListCon<in T>
{}
public class FasterList<T> : IList<T>, IFasterListCov<T>, IFasterListCon<T>
第三次施法失败:
public void QueryNodes<T>() where T:INode
{
//somehow I can convert IFasterListCon<INode> to IFasterListCon<T>
IFasterListCon<INode> nodes = (IFasterListCon<INode>)_nodesDB[type];
//I guess this works because _nodesDB[type] is indeed a FasterList<T> object
//note: I am wrong, I can cast whatever INode implementation, not just T, which made me very confused :P
IFasterListCon<T> nodesT = (IFasterListCon<T>)nodes;
//I can't cast IFasterListCon<T> back to FasterList<T>
FasterList<T> nodeI = nodesT as FasterList<T>; //null
}
Dictionary<Type, IFasterListCov<INode>> _nodesDB;
to be clear _nodesDB[type] is a FasterList<T> declared through IFasterListCov<INode>
在您调用 QueryNodes<MyNode>
的情况下,为了让您的最后一次转换获得非空值,您使用 _nodesDB[type]
获得的实际实例必须是 FasterList<MyNode>
。 FasterList<SomeOtherMostlyCompatibleNode>
.
运行时对类型非常严格,它跟踪所涉及的所有内容的实际运行时类型,数据类型相似或只有 MyNode
个对象填充是不够的您的 FasterList<SomeOtherMostlyCompatibleNode>
,或其他任何内容。如果类型不完全它们应该是什么,您需要进行某种编程转换,而不仅仅是转换。
MyType : IMyType
不会使 Generic<IMyType>
和 Generic<MyType>
有任何关联。
在您的特定情况下,nodesT
很可能是 FasterList<Node>
,而 不是 FasterList<INode>
.
请注意,当您可以指定 in
/out
时,此转换适用于支持变体 (co/contra) 的接口,正如您在成功转换为接口时看到的那样。有关详细信息,请参阅许多问题之一 - 即 Generic Class Covariance.
关于 List
协方差也有很好的答案 - C# variance problem: Assigning List<Derived> as List<Base> 这表明 List<Derived>
和 List<Base>
不能相互转换:
List<Giraffes> giraffes = new List<Giraffes>();
List<Animals> animals = new List<Animals>() {new Lion()};
(giraffes as List<Animals>).Add(new Lion()); // What? Lion added to Girafes
Giraffe g = (animals as List<Giraffes>)[0] ; // What? Lion here?