Подтвердить что ты не робот

Есть ли один сингл "Empty 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>() - который служит этой цели, хотя я не уверен, что аналогичная концепция может работать даже на С#, поскольку дженерики обрабатываются по-разному.

Спасибо.

4b9b3361

Ответ 1

Вы ищете Enumerable.Empty<int>();

В других новостях пустая строка Java сосет, потому что интерфейс List предоставляет методы добавления элементов в список, которые генерируют исключения.

Ответ 3

Я думаю, что вы ищете Enumerable.Empty<T>().

Пустой список singleton не имеет особого смысла, поскольку списки часто изменяются.

Ответ 4

Я думаю, что добавление метода расширения является чистой альтернативой благодаря их способности обрабатывать нули - что-то вроде:

  public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list)
  {
    return list ?? Enumerable.Empty<T>();
  }

  foreach(var x in xs.EmptyIfNull())
  {
    ...
  }

Ответ 5

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
}

Ответ 6

Использование Enumerable.Empty<T>() со списками имеет недостаток. Если вы передадите Enumerable.Empty<T> в конструктор списка, тогда выделяется массив размера 4. Но если вы передадите пустой Collection в конструктор списка, то распределение не произойдет. Поэтому, если вы используете это решение во всем своем коде, то, скорее всего, один из IEnumerable будет использоваться для построения списка, что приведет к ненужным выделениям.