Ответ 1
Вы ищете Enumerable.Empty<int>();
В других новостях пустая строка Java сосет, потому что интерфейс List предоставляет методы добавления элементов в список, которые генерируют исключения.
В С# я использую 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
Теперь, когда выше это отлично для меня - то есть, если есть какие-то дополнительные накладные расходы при создании объекта массива, мне просто все равно - мне было интересно:
Есть ли "пустой неизменяемый IEnumerable/IList" singleton в С#/. NET? (И, даже если нет, есть ли "лучший" способ справиться с описанным выше случаем?)
Java имеет Collections.EMPTY_LIST
неизменяемый синглтон - "хорошо типизированный" через Collections.emptyList<T>()
- который служит этой цели, хотя я не уверен, что аналогичная концепция может работать даже на С#, поскольку дженерики обрабатываются по-разному.
Спасибо.
Вы ищете Enumerable.Empty<int>();
В других новостях пустая строка Java сосет, потому что интерфейс List предоставляет методы добавления элементов в список, которые генерируют исключения.
Enumerable.Empty<T>()
- это именно то, что.
Я думаю, что вы ищете Enumerable.Empty<T>()
.
Пустой список singleton не имеет особого смысла, поскольку списки часто изменяются.
Я думаю, что добавление метода расширения является чистой альтернативой благодаря их способности обрабатывать нули - что-то вроде:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list)
{
return list ?? Enumerable.Empty<T>();
}
foreach(var x in xs.EmptyIfNull())
{
...
}
Microsoft реализовала `Any() 'как это (source)
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
будет использоваться для построения списка, что приведет к ненужным выделениям.