简体   繁体   English

关于协方差的困惑

[英]Confusion about covariance

I am developing a generic class and related generic methods. 我正在开发泛型类和相关的泛型方法。 I believe the problem I am about to describe has to do with Covariance, but I can't figure out what the compiler wants me to do. 我相信我要描述的问题与协方差有关,但我无法弄清楚编译器要我做什么。

Edit: adding code which shows how I populate the dict 编辑:添加显示我如何填充字典的代码

There is abstract base class NetworkNode. 有抽象基类NetworkNode。 Concrete class PowerNetworkNode inherits from it. 具体的类PowerNetworkNode继承自它。 Now I have a function which will not compile. 现在,我有一个无法编译的函数。 What changes should I make to get this to compile and have the desired functionality? 我应该进行哪些更改才能使其编译并具有所需的功能?

In abc NetworkNode, we have 在abc NetworkNode中,我们有

public abstract IDictionary<uint, NetworkNode> 
        hydrateNodes<NetworkNode>(string nodesTableName);

In the concrete class, PowerNetworkNode, this is overridden by 在具体的类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;
    }

The compiler error message is: 编译器错误消息是:

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?)

When I change the code to this: 当我将代码更改为此:

public override IDictionary<uint, NetworkNode> 
        hydrateNodes<NetworkNode>(string nodesTableName)
    {
        IDictionary<uint, NetworkNode> returnDict = 
             new Dictionary<uint, PowerNetworkNode>();

        // code elided

        return returnDict;
    }

in which the line with "new Dictionary" now creates one with NetworkNode and not PowerNetworkNode, the compiler states 在其中“新字典”所在的行现在使用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?)

I understand what this means, but I don't know what I should change to get it to work. 我了解这意味着什么,但是我不知道我应该进行哪些更改才能使其正常工作。

You have at least two misconceptions here - even before you reach your question - which is conflating the problem. 您至少在这里有两个误解-甚至在您提出问题之前-就将问题混为一谈。

Generic type parameter names 通用类型参数名称

The first issue has nothing to do with variance. 第一个问题与方差无关。 Understand that this: 了解这一点:

public override IDictionary<uint, NetworkNode> 
    hydrateNodes<NetworkNode>(string nodesTableName)
{
    IDictionary<uint, NetworkNode> returnDict = 
         new Dictionary<uint, PowerNetworkNode>();
}

Is exactly equivalent to this: 与此完全相同

public override IDictionary<uint, NetworkNode> 
    hydrateNodes<T>(string nodesTableName)
{
    IDictionary<uint, T> returnDict = 
         new Dictionary<uint, PowerNetworkNode>();
}

That is, the generic type parameter in the method name does not refer to an actual type, it just refers to what you are going to call that type in the method . 也就是说,方法名称的泛型类型参数不引用实际类型,而只是引用您将在方法中调用该类型的内容 If you call a method public void DoSomething<SomeClass> , this has nothing to do with a class called SomeClass . 如果将方法称为public void DoSomething<SomeClass> ,则与名为SomeClass的类无关。

It should be clear from the above that you can't assign a Dictionary<uint, PowerNetworkNode> to a IDictionary<uint, T> - you have no idea whether a PowerNetworkNode is a T . 从上面应该清楚地知道,您不能将Dictionary<uint, PowerNetworkNode>分配给IDictionary<uint, T> -您不知道PowerNetworkNode是否为T

However, if you look a little more closely, you'll realise that this method doesn't need to be generic at all - you always want T to be a NetworkNode, so just... 但是,如果您仔细观察一下,您会发现此方法根本不需要通用-您始终希望T成为NetworkNode,所以...

public override IDictionary<uint, NetworkNode> 
    hydrateNodes(string nodesTableName)
{
    IDictionary<uint, NetworkNode> returnDict = 
         new Dictionary<uint, PowerNetworkNode>();
}

This is a step in the right direction but it leads to your next problem. 这是朝正确方向迈出的一步,但它会导致您遇到下一个问题。

Variance 方差

As you know, IDictionary<TKey, TValue> is invariant in TValue , so you can't assign a Dictionary<uint, PowerNetworkNode> to a IDictionary<uint, NetworkNode> . 如您所知, IDictionary<TKey, TValue>TValue是不变的,因此您不能将Dictionary<uint, PowerNetworkNode>分配给IDictionary<uint, NetworkNode>

Now, you've mentioned in the comments that you want "a key/value pair type that is covariant in its value." 现在,您已经在注释中提到想要“键/值对类型,其值是协变的”。

Bad news - you can't have one of those. 坏消息-您不能选择其中之一。 It's inherently a contradiction. 本质上是自相矛盾。 If you declare something as Something<NetworkNode> where you can add a NetworkNode, the compiler expects you to be able to add any NetworkNode to it. 如果您将某些内容声明为Something<NetworkNode> ,可以在其中添加 NetworkNode,则编译器希望您能够向其中添加任何NetworkNode If you assign a Something<PowerNetworkNode> to that - you've broken that contract. 如果为它分配Something<PowerNetworkNode> -您就违反了合同。 That's why invariance exists: because it is a logical necessity. 这就是为什么存在不变性:因为这是逻辑上的必要性。

The good news is that you shouldn't need to - you can put a PowerNetworkNode in an IDictionary<uint, NetworkNode> - because a PowerNetworkNode is a NetworkNode . 消息是,您不需要-可以将PowerNetworkNode放入IDictionary<uint, NetworkNode> -因为PowerNetworkNodeNetworkNode

So (unless you're doing something very strange in the rest of the method), the following should be fine: 因此(除非您在该方法的其余部分中做的很奇怪),以下内容应该没问题:

public override IDictionary<uint, NetworkNode> 
    hydrateNodes(string nodesTableName)
{
    IDictionary<uint, NetworkNode> returnDict = 
         new Dictionary<uint, NetworkNode>();
}

Hopefully this has provided some insight. 希望这提供了一些见识。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM