Изучая LINQ наткнулся на то, что результат запроса имеет такой тип, но информации по нему найти не удалось.
Информации не удалось найти из-за закона Деметры.
объект должен иметь как можно меньше представления о структуре и свойствах чего угодно
Класс WhereSelectArrayIterator
реализует Декоратор и Адаптер Итератора. Декоратор, Адаптер и Итератор — три паттерна, описанные в классической книге GoF.
Метод Enumerable.Select
получает на вход Итератор (любой класс, реализующий интерфейс IEnumerable<T>
) и возвращает другой Итератор. Новый Итератор является Адаптером потому что преобразует интерфейс IEnumerable<T1>
в интерфейс IEnumerable<T2>
.
Для того, чтобы вызывать метод Select
нам достаточно знать только, что на входе и выходе у нас IEnumerable<T>
. По закону Деметры знать реальный тип возвращаемого объекта нам не нужно.
Если мы не знаем деталей реализации, то создатели LINQ вольны выбирать любую реализацию, и наш код продолжит работать корректно.
Как видим, создатели LINQ, очевидно, в целях минимизации кода, сделали один класс для выполнения двух разных операций: Where и Select. Так что здесь реализован не только паттерн Адаптер, но и паттерн Декоратор, который добавляет новое поведение, а именно фильтрацию. В целях оптимизации они сделали разные классы для коллекций тех типов, с которыми они умеют работать быстро в обход стандартного интерфейса, а именно, для списков и для массивов.
Таким образом, получились классы WhereSelectArrayIterator<T1, T2>
и WhereSelectListIterator<T1, T2>
. Каждый из них, в зависимости от параметров конструктора, выполняет фильтрацию и отображение входной последовательности IEnumerable<T1>
в выходную последовательность IEnumerable<T2>
. Первый предназначен для быстрой обработки массивов, а второй — списков. Это то, что мы можем предположить. При прочих равных условиях большего знать нам и не нужно.
Этот тип возвращается функцией Select
при следующих вызовах если она применена к массиву:
arr.Select(...)
arr.Select(...).Select(...)
arr.Where(...).Select(...)
arr.Where(...).Select(...).Select(...)
arr.Where(...).Where(...).Select(...)
И так далее.
Вот прямо так и проверяют:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
// ...
if (source is TSource[])
{
return new Enumerable.WhereSelectArrayIterator<TSource, TResult>((TSource[])source, null, selector);
}
// ...
}
Смысл существования данного класса - оптимизация LINQ при работе с массивами. Данный класс реализует интерфейсы IEnumerable и IEnumerator.
Исходный код этого класса можно увидеть тут: https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L418
Реализация IEnumerator<TResult>
у этого класса тривиальная - просто хранится индекс текущего элемента в поле index
, в методе MoveNext
он увеличивается пока не дойдет до допустимого элемента или до конца массива.
Реализация IEnumerable<TResult>
у этого класса сложнее и спрятана в базовом классе Iterator<TResult>
. Там используется популярный трюк для уменьшения нагрузки на сборщик мусора: в методе GetEnumerator()
делается проверка что объект создан в текущем потоке и что метод GetEnumerator()
еще ни разу не вызывался; если это так то возвращается this
, иначе возвращается новый объект.
Наконец, довольно важной частью являются методы Select
и Where
, которые используются для оптимизации построения цепочек из методов LINQ.
Метод Select
возвращает новый WhereSelectArrayIterator
, тем самым позволяя тянуть цепочку из вызовов .Select()
сохраняя оптимальный доступ к массиву.
Метод Where
не дает новых оптимизаций, но нужен потому что объявлен абстрактным в базовом классе. Он возвращает WhereEnumerableIterator
который работает с произвольной последовательностью.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Нужно написать программу чтобы получить данные(таблицы) из 1С в с#примерно так же как брать данные с базы данных access
В официальной документации сказано что юнити понимает partial классы шарпаВот мой пример: