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



спасибо.

734   7  

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>()

, который поможет вам избежать ненужных выделений.

Заметки / Ссылки:

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

    Ничего не найдено.