В C # я хорошо использую LINQ и IEnumerable. И все хорошо (по крайней мере, в большинстве случаев).
Однако во многих случаях я считаю, что мне нужно пустое поле IEnumerable<X>
по умолчанию. То есть я бы хотел
for (var x in xs) { ... }
чтобы работать без проверки нуля. Вот что я сейчас делаю, в зависимости от более широкого контекста:
var xs = f() ?? new X[0]; // when xs is assigned, sometimes
for (var x in xs ?? new X[0]) { ... } // inline, sometimes
Теперь, хотя все вышесказанное для меня совершенно нормально - то есть, если есть какие-то «дополнительные накладные расходы» при создании объекта массива, мне просто все равно - мне было интересно:
Есть ли в C # /. NET "пустой неизменяемый синглтон IEnumerable / IList"? (И даже если нет, есть ли «лучший» способ справиться с описанным выше случаем?)
В Java есть Collections.EMPTY_LIST
неизменяемый синглтон - «хорошо типизированный» переход, Collections.emptyList<T>()
который служит этой цели, хотя я не уверен, может ли аналогичная концепция вообще работать в C #, потому что универсальные шаблоны обрабатываются по-разному.
Благодарю.
public static class Array<T> { public static readonly T[] Empty = new T[0]; }
и это можно назвать как:Array<string>.Empty
. Я спросил об этом здесь, в CodeReview .Ответы:
Вы ищите
Enumerable.Empty<T>()
.К другим новостям, пустой список Java - отстой, потому что интерфейс List предоставляет методы для добавления элементов в список, которые вызывают исключения.
источник
List
(коллекцию, доступ к которой можно получить по индексу). ТеList
могут быть неизменяемые. А иногда нужно вернуть такой readonlyList
с нулевым элементом. Итак,Collections.emptyList()
метод. Вы не можете просто вернуть пустой Iterable, потому что реализованный интерфейс указывает, что метод возвращает список. Большая проблема в том, что у них нет интерфейса ImmutableList, который вы можете вернуть. Та же проблема существует и в .NET: любойIList
может быть доступен только для чтения.Enumerable.Empty<T>()
именно это.источник
Array.Empty<T>()
уж просили "список", точнее, так как этоIList<T>
. Это приносит радость, так как приносит удовлетворениеIReadOnlyCollection<T>
. Конечно, гдеIEnumerable<T>
делает хватает,Enumerable.Empty<T>()
идеально подходит.Array.Empty<T>
стали доступны. :) В любом случае, несмотря на заголовок, вопрос ясно дает понять, что anIEnumerable<T>
подходит для этой цели.Думаю, ты ищешь
Enumerable.Empty<T>()
.Синглтон с пустым списком не имеет особого смысла, потому что списки часто изменяемы.
источник
В исходном примере вы используете пустой массив для предоставления пустого перечислимого. Хотя использование
Enumerable.Empty<T>()
совершенно правильно, могут быть и другие случаи: если вам нужно использовать массив (илиIList<T>
интерфейс), вы можете использовать методчто помогает избежать ненужных выделений.
Примечания / ссылки:
источник
Я думаю, что добавление метода расширения - это чистая альтернатива благодаря их способности обрабатывать нули - что-то вроде:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list) { return list ?? Enumerable.Empty<T>(); } foreach(var x in xs.EmptyIfNull()) { ... }
источник
Microsoft реализовала `Any () 'следующим образом ( источник )
public static bool Any<TSource>(this IEnumerable<TSource> source) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return true; } return false; }
Если вы хотите сохранить вызов в стеке вызовов, вместо того, чтобы писать вызывающий метод расширения
!Any()
, просто перезапишите эти три изменения:public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) //first change (name) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return false; //second change } return true; //third change }
источник
Использование
Enumerable.Empty<T>()
со списками имеет недостаток. Если вы перейдетеEnumerable.Empty<T>
в конструктор списка, то будет выделен массив размером 4. Но если вы передаете пустое значениеCollection
в конструктор списка, распределения не происходит. Поэтому, если вы используете это решение во всем своем коде, то, скорее всего,IEnumerable
для создания списка будет использоваться один из s, что приведет к ненужным выделениям.источник