C#为什么这里不需要显式演员?

BoS*_*YyY 3 .net c# casting

如果没有明确的演员,这段代码如何运作?

static void Main()
{
    IList<Dog> dogs = new List<Dog>();
    IEnumerable<Animal> animals = dogs;
}
Run Code Online (Sandbox Code Playgroud)

我在谈论这一行:

IEnumerable<animal> animals = dogs;
Run Code Online (Sandbox Code Playgroud)

你可以在这里看到我能够在没有明确演员的情况下传递变量狗.但这怎么可能呢?为什么编译器允许我这样做?我不应该先做这样的演员:

IEnumerable<Animal> animals = (List<Dog>) dogs;
Run Code Online (Sandbox Code Playgroud)

代码将使用显式强制转换而不使用显式强制转换但我无法理解为什么它允许我在没有显式强制转换的情况下将狗分配给animals引用变量.

Jon*_*eet 8

IEnumerable<T>是一个协变的接口.这意味着有一个由隐式标识转换IEnumerable<T1>IEnumerable<T2>只要有一个隐式引用转换标识转换T1T2.有关此术语的更多详细信息,请参阅有关转换文档.

如果T2是基类(直接或间接)T1,或者是T1实现的接口,则最常见的情况.这也是如果案件T1T2是相同的类型,或者T2dynamic.

在你的情况下,你正在使用IList<Dog>IList<T>实现IEnumerable<T>.这意味着任何IList<Dog>也是一个IEnumerable<Dog>,所以有一个隐式的引用转换IEnumerable<Animal>.

需要注意的几件重要事项:

只有在安全的情况下才允许通用差异:

  • 协方差依赖于类型参数仅存在于任何签名中的"out"位置,即值可以来自实现,但是从不被接受.
  • 逆变量依赖于类型参数仅存在于任何签名中的"输入"位置,即值可以传递到实现中,但永远不会返回

当签名接受一个本身是逆变的参数时,它会有点混乱 - 即使一个参数通常是一个"输入"位置,它也会因逆变而逆转.例如:

public interface Covariant<out T>
{
    // This is valid, because T is in an output position here as
    // Action<T> is contravariant in T
    void Method(Action<T> input);
}
Run Code Online (Sandbox Code Playgroud)

绝对阅读链接文档以获取更多信息!