简体   繁体   English

使用IList和IEnumerable的通用逆变量

[英]Using generic contravariant with IList and IEnumerable

I'm learning C# generics and making some dummy code for testing purposes. 我正在学习C#泛型并为测试目的制作一些虚拟代码。 So, I'm testing the in Generic Modifier , which specifies that the type parameter is contravariant. 所以,我正在测试Generic Modifier ,它指定type参数是逆变的。

Given the below interface: 鉴于以下界面:

public interface IInterfaceTest<in T>
{
    void Method(T value);
    void Method(IList<T> values);
    void Method(IEnumerable<T> values);
}

When compiling, I'm getting the error message: 编译时,我收到错误消息:

[CS1961] Invalid variance: The type parameter 'T' must be invariantly valid on 'IInterfaceTest.Method(IList)'. [CS1961]无效方差:类型参数“T”必须在“IInterfaceTest.Method(IList)”上无效有效。 'T' is contravariant. 'T'是逆变的。

The error is related only with the line void Method(IEnumerable<T> values) . 该错误仅与行void Method(IEnumerable<T> values) If this line is removed, all works fine. 如果删除此行,则一切正常。

So my question is: Why can I use the generic contravariant with IEnumerable but does not with IList ? 所以我的问题是:为什么我可以使用IEnumerable的通用逆变,但不能使用IList Am I forgot something? 我忘记了什么吗?

Thanks. 谢谢。

The question why it's not allowed for IList<T> has been answered in the comments and linked questions already: IList<T> is invariant in T and so a contra-variant T cannot be used here whatsoever. 已经在评论和相关问题中回答了为什么不允许IList<T>问题: IList<T>T是不变的,因此这里不能使用反变量T

What puzzled me at first is the fact that Method(IEnumerable<T>) is allowed here. 最让我困惑的是这里允许使用Method(IEnumerable<T>)这一事实。 The strange thing is that variance is "turned around" when you use the T as a type argument for another generic type . 奇怪的是,当你使用T作为另一个泛型类型的类型参数时, 方差被“转过来”

Imagine this. 想象一下。

public interface ITestInterface<in T>
{
    void Method(IEnumerable<T> e);
    IEnumerable<T> GetMethod(); // illegal
}
public class Animal {}
public class Lion : Animal [}
public class Gnu : Animal {}

ITestInterface<Animal> animals;
ITestInterface<Lion> lions;
ITestInterface<Gnu> gnus;

Now the contra-variance of ITestInterface<in T> in T tells us that you can do 现在的禁忌方差ITestInterface<in T>T告诉我们,你可以做

lions = animals;

And when you call lions.Method(e) , you can only provide an IEnumerable<Lion> . 当你打电话给lions.Method(e) ,你只能提供一个IEnumerable<Lion> So the code of Method can only enumerate Lion s, which are all Animals as animals.Method() expects. 因此, Method的代码只能枚举Lion s,它们都是 Animals作为animals.Method()期望的。 Everything is fine. 一切都好。

On the other hand, the IEnumerable<T> GetMethod() is illegal, because: 另一方面, IEnumerable<T> GetMethod()是非法的,因为:

gnus = animals;

is legal, and now gnu.GetMethod() would return an IEnumerable<Animal> where you'd expect an IEnumerable<Gnu> . 是合法的,现在gnu.GetMethod()将返回一个IEnumerable<Animal> ,你期望IEnumerable<Gnu> And when you iterated, suprising animals could wait in that sequence. 当你迭代时,令人惊讶的动物可以按照那个顺序等待。

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

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