Есть ли" пустой список " синглтон в C#?
в C# я использую LINQ и IEnumerable хороший бит. И все хорошо (или, по крайней мере, в основном так).
однако во многих случаях я обнаруживаю, что мне нужен пустой IEnumerable<X> по умолчанию. То есть, я бы хотел
for (var x in xs) { ... }
для работы без использования null-проверка. Теперь это то, что я сейчас делаю, в зависимости от более широкого контекста:
var xs = f() ?? new X[0]; // when xs is assigned, sometimes
for (var x in xs ?? new X[0]) { ... } // inline, sometimes
теперь, в то время как выше прекрасно для меня -- то есть, если есть какие-либо "дополнительной нагрузки" с созданием объекта массива I все равно -- мне было интересно:
есть ли" пустой неизменяемый IEnumerable/IList " синглтон в C# / .NET? (и, даже если нет, есть ли "лучший" способ справиться с описанным выше случаем?)
Java имеет Collections.EMPTY_LIST неизменяемый синглтон -- "хорошо набранный" через Collections.emptyList<T>() -- что служит этой цели, хотя я не уверен, что подобная концепция могла даже работать в C#, потому что дженерики обрабатываются по-разному.
спасибо.
7 ответов:
вы ищете
Enumerable.Empty<int>();в других новостях пустой список Java отстой, потому что интерфейс списка предоставляет методы для добавления элементов в список, которые выбрасывают исключения.
Enumerable.Empty<T>()именно так.
Я думаю, что вы ищете
Enumerable.Empty<T>().пустой список синглтон не имеет большого смысла, потому что списки часто изменчивы.
Я думаю, что добавление метода расширения является чистой альтернативой благодаря их способности обрабатывать нули - что-то вроде:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list) { return list ?? Enumerable.Empty<T>(); } foreach(var x in xs.EmptyIfNull()) { ... }
в исходном примере вы используете пустой массив для предоставления пустого перечисляемого. При использовании
Enumerable.Empty<T>()совершенно верно, могут быть и другие случаи: если вы использовать массив (илиIList<T>интерфейс), вы можете использовать методSystem.Array.Empty<T>(), который поможет вам избежать ненужных выделений.
Заметки / Ссылки:
- the документация не упоминает, что этот метод выделяет только пустой массив один раз для каждого типа
- анализаторы Рослин рекомендуем этот метод с предупреждением CA1825: избегайте выделения массива нулевой длины
- Microsoft эталонной реализации
- реализация .NET Core
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в конструктор списка, то выделение не происходит. Поэтому, если вы используете это решение во всем своем коде, то, скорее всего, один изIEnumerables будет использоваться для построения списка,что приведет к ненужным распределениям.
Comments