LINQ中AsEnumerable()的内部实现

RaM*_*RaM 9 c# linq compiler-construction covariance contravariance

我有两个问题:

问题1背景: 当我在Microsoft的LINQ中查看'AsEnumerable()'方法的实现时,我注意到了:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{ 
   return source;
} 
Run Code Online (Sandbox Code Playgroud)

问题1: 我期待某种铸造或某种东西在这里,但它只是返回它传递的值.这是如何运作的 ?

问题2/3背景: 我一直在努力理解协方差,逆变和不变性.我认为,我有一个模糊的理解,即'in'和'out'关键字确定将子类型分配给父类型时的多态行为.

问题2: 我从阅读中知道IEnumerable是协变的,而List是不变的,那么为什么这是不可能的:

List<char> content = "testString".AsEnumerable();
Run Code Online (Sandbox Code Playgroud)

问题3:
如果IList实现了IEnumerable,那么为什么这是不可能的:

IEnumerable<char> content1 = "testString";
IList<char> content2 = content1;
Run Code Online (Sandbox Code Playgroud)

请帮我理解,提前谢谢.

Mag*_*ken 3

  1. 已知输入参数的类型为IEnumerable<TSource>。为什么需要投射任何东西?将对象转换为该类型TSource不会有任何效果,因为它们已经保证是该类型(或更派生的类型)。

  2. 您不能将 type 的值分配IEnumerable<char>给 type 的变量List<char>。我认为你在这里想的是相反的;List<char>源自IEnumerable<char>,而不是相反。List<T>这与不变性无关。IEnumerable<T>是协变的(更准确地说,类型参数T是协变的),这给了我们这样的情况:

    IEnumerable enumerable = Enumerable.Empty<string>(); // Allowed
    IEnumerable<string> genericEnumerable = enumerable; // Not allowed
    
    Run Code Online (Sandbox Code Playgroud)
  3. 同样,IList<char>继承自IEnumerable<char>,而不是相反。你可以这样做:

    IList<char> content1 = "testString".ToList();
    IEnumerable<char> content2 = content1;
    
    Run Code Online (Sandbox Code Playgroud)

    恐怕你所要求的没有意义,而且与协方差无关。协变的事实IEnumerable<T>意味着您可以这样做:

    IEnumerable<object> asObject = new List<string>() { "test" };
    
    Run Code Online (Sandbox Code Playgroud)

    但它List<T>是不变的,所以你不能这样做:

    List<object> asObject = new List<string>() { "test" };
    
    Run Code Online (Sandbox Code Playgroud)