【问题标题】:Contravariance/Covariance, why can't cast this?逆变/协方差,为什么不能投这个?
【发布时间】:2016-05-19 20:56:48
【问题描述】:

面对现实吧,当需要在泛型中使用协变和逆变时,我仍然难以理解约束。

我想知道,为什么我有这个:

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>

【问题讨论】:

  • nodesT实际 类型是什么?你正在做一个 downcast 只有在底层类型兼容的情况下才有效。
  • 你的意思是什么是T? T 必须实现 INode(约束在 where 子句中)...啊 好的 _nodesDB 包含所有 FasterList
  • 除非TINode,否则FasterList&lt;INode&gt; 不是FasterList&lt;T&gt;
  • 所以 T 实现 INode 还不够?我的意思是在内存中仍然是两种情况下的参考,对吗?数据结构应该是兼容的。

标签: c# casting covariance contravariance


【解决方案1】:

MyType : IMyType 不会以任何方式使 Generic&lt;IMyType&gt;Generic&lt;MyType&gt; 相关。

在您的特定情况下,nodesT 很可能是 FasterList&lt;Node&gt;,而 不是 FasterList&lt;INode&gt;

请注意,当您可以指定in/out 时,此转换适用于支持方差(co/contra)的接口,正如您在成功转换为接口时看到的那样。有关详细信息,请参阅许多问题之一 - 即 Generic Class Covariance

关于List co-variance - C# variance problem: Assigning List<Derived> as List<Base> 也有很好的答案,这表明List&lt;Derived&gt;List&lt;Base&gt; 不能相互转换:

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?

【讨论】:

  • FasterList 不是 FasterList 即使 Node 实现了 INode?​​span>
  • 是的 - 看到 Giraffes 的精彩解释 - stackoverflow.com/questions/2033912/…(谈论具体的类,但它同样适用于接口/类对)
  • 好的,我知道该语言想要保护 FasterList 被强制转换为 IFasterListCon ......但在这种情况下,情况正好相反。我正在投专业化,而不是泛化。
  • @sebas 我已经根据 Jon 的回答用样本更新了我的回答,这可能很清楚。
  • 好吧,我想我明白了,IFasterListCov 可能持有不同类型的 INode...我的困惑是因为我从错误的角度看它。我将 IFasterListCov 视为 FasterList 的概括,而不是将 INode 视为 T 的概括。顺便说一句,这也是一个很好的答案:stackoverflow.com/questions/2719954/…
【解决方案2】:

在您调用QueryNodes&lt;MyNode&gt; 的场景中,为了使您的最后一次转换获得非空值,您使用_nodesDB[type] 获得的实际实例必须是FasterList&lt;MyNode&gt;FasterList&lt;SomeOtherMostlyCompatibleNode&gt; 不够好。

运行时对类型非常严格,它跟踪所涉及的所有内容的实际运行时类型,这不足以让数据类型相似,或者你只有MyNode 对象填充你的FasterList&lt;SomeOtherMostlyCompatibleNode&gt; ,或其他任何东西。如果类型不是完全应有的类型,则需要进行某种编程转换,而不仅仅是强制转换。

【讨论】:

  • wait sorry,我没说清楚...FasterList 节点包含MyNode 元素,只是我通过INode 声明的。所以 FasterList.Add(MyNode)...伪代码如果有意义的话。
猜你喜欢
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 2014-09-01
相关资源
最近更新 更多