Внутренняя реализация AsEnumerable() в LINQ

У меня есть два вопроса:

Вопрос 1. Предыстория: при просмотре реализации метода AsEnumerable() в LINQ от Microsoft я заметил следующее:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{ 
   return source;
} 

Вопрос 1: я ожидал здесь какого-то кастинга или чего-то подобного, но он просто возвращает переданное значение. Как это работает ?

Вопрос 2/3 Предыстория: я пытался понять ковариацию, контравариантность и инвариант. Я думаю, у меня есть смутное понимание того, что ключевые слова «in» и «out» определяют полиморфное поведение при назначении подтипа родительскому типу.

Вопрос 2: я знаю из чтения, что IEnumerable является ковариантным, а List инвариантным, тогда почему это невозможно:

List<char> content = "testString".AsEnumerable();

Вопрос 3.
Если IList реализует IEnumerable, то почему это невозможно:

IEnumerable<char> content1 = "testString";
IList<char> content2 = content1;

Пожалуйста, помогите мне понять, спасибо заранее.


person RaM    schedule 31.07.2013    source источник
comment
AsEnumerable() заставляет запрос немедленно выполняться в других поставщиках LINQ, таких как LINQ to SQL или Entity Framework. Вероятно, он добавлен в LINQ to Objects для полноты картины.   -  person Ufuk Hacıoğulları    schedule 31.07.2013


Ответы (1)


  1. Уже известно, что входной аргумент имеет тип IEnumerable<TSource>. Зачем ему что-то бросать? Приведение объектов к типу TSource не будет иметь никакого эффекта, поскольку они уже гарантированно относятся к этому типу (или более производному типу).

  2. Вы не можете присвоить значение типа IEnumerable<char> переменной типа List<char>. Я думаю, вы думаете здесь наоборот; List<char> происходит от IEnumerable<char>, а не наоборот. Это не имеет ничего общего с инвариантностью List<T>. IEnumerable<T> является ковариантным (точнее, параметр типа T является ковариантным), что дает нам такую ​​ситуацию:

    IEnumerable enumerable = Enumerable.Empty<string>(); // Allowed
    IEnumerable<string> genericEnumerable = enumerable; // Not allowed
    
  3. Опять же, IList<char> наследуется от IEnumerable<char>, а не наоборот. Ты можешь это сделать:

    IList<char> content1 = "testString".ToList();
    IEnumerable<char> content2 = content1;
    

    Боюсь, то, о чем вы просите, не имеет смысла, и это не имеет ничего общего с ковариацией. Тот факт, что IEnumerable<T> является ковариантным, означает, что вам разрешено делать это:

    IEnumerable<object> asObject = new List<string>() { "test" };
    

    Но List<T> является инвариантным, поэтому вы не можете сделать это:

    List<object> asObject = new List<string>() { "test" };
    
person Community    schedule 31.07.2013
comment
Мне нужно время, чтобы переварить это! - person RaM; 31.07.2013
comment
В ответ на 1-й ответ я понимаю, поэтому, если я могу напрямую присвоить значение производного объекта экземпляру родительского типа, то какую цель решает «AsEnumerable ()»? - person RaM; 31.07.2013
comment
В ответ на 2-й ответ, хорошо, почему IEnumerable‹string› enumerable = (IEnumerable)Enumerable.Empty‹string›(); невозможно ? IEnumerable‹T› реализует IEnumerable, так почему компилятор жалуется? - person RaM; 31.07.2013
comment
@RaM Ты снова думаешь наоборот. IEnumerable<T> реализует IEnumerable, что означает, что вы можете присвоить экземпляр IEnumerable<T> переменной типа IEnumerable, а не наоборот. В приведенном вами примере компилятор не знает, что переменная на самом деле является экземпляром IEnumerable<string>. Я отредактировал пример, надеюсь, он станет немного понятнее. - person Magnus Grindal Bakken; 31.07.2013
comment
Что касается AsEnumerable(), я, честно говоря, тоже не очень уверен, в чем его смысл. В разделе примечаний статьи MSDN указано, что его можно использовать для скрывать специальные реализации других методов LINQ, таких как Where и Select, но мне это кажется странным объяснением. Может быть, он мне просто никогда не был нужен. - person Magnus Grindal Bakken; 31.07.2013
comment
@MagnusGrindalBakken AsEnumerable очень полезен в LINQ to SQL/EF, поскольку он разделяет серверную (перевод) и клиентскую обработку оператора LINQ. - person NetMage; 11.10.2019