我正在开发一个泛型类和相关的泛型方法。我相信我要描述的问题与Covariance有关,但我无法弄清楚编译器要我做什么。
编辑:添加代码,显示我如何填充字典
有抽象基类NetworkNode。具体类PowerNetworkNode继承自它。现在我有一个无法编译的函数。我应该做些什么改变才能编译并拥有所需的功能?
在abc NetworkNode中,我们有
public abstract IDictionary<uint, NetworkNode>
hydrateNodes<NetworkNode>(string nodesTableName);
在具体的类PowerNetworkNode中,这被
覆盖public override IDictionary<uint, NetworkNode>
hydrateNodes<NetworkNode>(string nodesTableName)
{
IDictionary<uint, PowerNetworkNode> returnDict =
new Dictionary<uint, PowerNetworkNode>();
// code elided
returnDict[Convert.ToUInt32(oid)] =
new PowerNetworkNode(oid, minPow, maxPow, edges, fuelType, ngID);
// NetworkNode doesn't have all the fields that PowerNetworkNode has.
return returnDict;
}
编译器错误消息是:
Error CS0266 Cannot implicitly convert type
'System.Collections.Generic.IDictionary<uint,
CImodeller.Model.NetworkElements.PowerNetworkNode>' to
'System.Collections.Generic.IDictionary<uint, NetworkNode>'.
An explicit conversion exists (are you missing a cast?)
当我将代码更改为:
public override IDictionary<uint, NetworkNode>
hydrateNodes<NetworkNode>(string nodesTableName)
{
IDictionary<uint, NetworkNode> returnDict =
new Dictionary<uint, PowerNetworkNode>();
// code elided
return returnDict;
}
其中带有“new Dictionary”的行现在用NetworkNode创建一个而不是PowerNetworkNode,编译器声明
Error CS0266 Cannot implicitly convert type
'System.Collections.Generic.Dictionary<uint,
CImodeller.Model.NetworkElements.PowerNetworkNode>' to
'System.Collections.Generic.IDictionary<uint, NetworkNode>'.
An explicit conversion exists (are you missing a cast?)
我明白这意味着什么,但我不知道应该改变什么来让它发挥作用。
答案 0 :(得分:3)
这里至少有两个误解 - 甚至在你提出问题之前 - 这使问题变得混乱。
第一个问题与方差无关。明白这一点:
public override IDictionary<uint, NetworkNode>
hydrateNodes<NetworkNode>(string nodesTableName)
{
IDictionary<uint, NetworkNode> returnDict =
new Dictionary<uint, PowerNetworkNode>();
}
与完全相同
:public override IDictionary<uint, NetworkNode>
hydrateNodes<T>(string nodesTableName)
{
IDictionary<uint, T> returnDict =
new Dictionary<uint, PowerNetworkNode>();
}
也就是说,方法名称中的泛型类型参数不会将引用到实际类型,它只是引用您将在方法中调用该类型的内容。如果您调用方法public void DoSomething<SomeClass>
,则这与名为SomeClass
的类无关。
从上面可以清楚地看出,您无法将Dictionary<uint, PowerNetworkNode>
分配给IDictionary<uint, T>
- 您不知道PowerNetworkNode
是否为T
。< / p>
但是,如果你仔细观察一下,你会发现这个方法根本不需要通用 - 你总是希望T
成为一个NetworkNode,所以只是...
public override IDictionary<uint, NetworkNode>
hydrateNodes(string nodesTableName)
{
IDictionary<uint, NetworkNode> returnDict =
new Dictionary<uint, PowerNetworkNode>();
}
这是向正确方向迈出的一步,但它会导致您的下一个问题。
如您所知,IDictionary<TKey, TValue>
中的TValue
不变,因此您无法将Dictionary<uint, PowerNetworkNode>
分配给IDictionary<uint, NetworkNode>
。
现在,您已在评论中提到“您希望”键值/值对的类型在其值中是协变的。“
坏消息 - 你不能拥有其中之一。这本质上是一个矛盾。如果您将<{1}}声明为添加 NetworkNode,则编译器希望您能够将任何NetworkNode 添加到其中。如果您为此分配Something<NetworkNode>
- 您已经违反了该合同。这就是不变性存在的原因:因为它是一种逻辑上的必然性。
好新闻是您不需要的 - 您可以在Something<PowerNetworkNode>
中加PowerNetworkNode
- 因为IDictionary<uint, NetworkNode>
是PowerNetworkNode
1}}。
所以(除非你在方法的其余部分做了一些非常奇怪的事情),以下情况应该没问题:
NetworkNode
希望这提供了一些见解。