Почему операции LINQ теряют статический тип коллекции? - PullRequest
1 голос
/ 23 июля 2011

Независимо от типа коллекции, которую я использую в качестве входных данных, LINQ всегда возвращает IEnumerable<MyType> вместо List<MyType> или HashSet<MyType>.

Из учебника MSDN :

int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

// numQuery is an IEnumerable<int> <====== Why IEnumerable<int> instead of int[]?
var numQuery =
    from num in numbers
    where (num % 2) == 0
    select num;

Интересно, каково обоснование решения не сохранять тип коллекции (например, тип элемента), а не предлагаемый обходной путь.

Я знаю, что toArray, toDictionary или toList существуют, вопрос не в этом.

Редактировать: Чем отличается реализация в C # от Scala, где она работает без повсеместного переопределения возвращаемых типов?

Ответы [ 5 ]

7 голосов
/ 23 июля 2011

Стандартные операторы запросов Linq определены для IEnumerable<T>, а не для любого другого конкретного типа коллекции. Это применимо к большинству коллекций, потому что все они реализуют IEnumerable<T>.

Вывод этих стандартных операторов запросов - новый IEnumerable<T> - если вы хотите поддерживать все доступные коллекции, вам потребуется N реализаций этих стандартных операторов запросов, а не один.

Также многие аспекты Linq, такие как ленивая оценка, не будут работать хорошо, если будут вынуждены работать, то есть List<T>, в отличие от IEnumerable<T>.

3 голосов
/ 23 июля 2011

Краткий ответ: Система типов C # слишком примитивна, чтобы поддерживать сохранение типа коллекции в функциях более высокого порядка (т.е. без дублирования кода).

Длинный ответ: См. Мой пост здесь . (На самом деле речь идет о Java, но относится и к C #.)

1 голос
/ 23 июля 2011

В конкретном случае LINQ-to-objects поставщик LINQ представляет собой набор методов расширения, определенных в классе System.Linq.Enumerable.Чтобы быть настолько универсальными, насколько это возможно, они определены для расширения любого типа, который реализует интерфейс IEnumerable<T>.Поэтому, когда эти методы выполняются, они не знают, к какому конкретному типу относится коллекция;он только знает, что это IEnumerable<T>.Из-за этого нельзя гарантировать, что операции, выполняемые над коллекцией, создают коллекцию того же типа.Таким образом, вместо этого он создает следующую лучшую вещь - объект IEnumerable<T>.

Это был очень специфический выбор дизайна.LINQ предназначен для работы на очень высоком уровне абстракции.Он существует для того, чтобы вам не приходилось заботиться об основных источниках данных, а вместо этого можно просто сказать, что вы хотите, а не заботиться о таких деталях.

0 голосов
/ 24 июля 2011

Многие методы System.Linq.Enumerable оцениваются лениво. Это позволяет создавать запрос без его выполнения.

//a big array - have to start somewhere
int[] source = Enumerable.Range(0, 1000000).ToArray();

var query1 = source.Where(i => i % 2 == 1); //500000 elements
var query2 = query1.Select(i => i.ToString()); //500000 elements
var query3 = query2.Where(i => i.StartsWith("2"); //50000? elements
var query4 = query3.Take(5); //5 elements

string[] result = query4.ToArray();

Этот код вызывает ToString примерно 15 раз. Он выделяет одну строку [5] массив.

Если Where и Select возвращали массивы, этот код вызвал бы ToString 500000 раз и должен был бы выделить два массивных массива. Слава Богу, что это не так.

0 голосов
/ 23 июля 2011

LINQ принимает IEnumerable <> и возвращает его. Очень естественно. Причина, по которой IEnumerable - это то, что берет LINQ, - практически все коллекции реализуют его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...