2010-10-08 1 views
29

Какой стандартный способ получить типизированный, только пустой список в C#, или он есть?C#/.NET эквивалент для коллекций Java. <T> emptyList()?

ETA: Для тех, кто спрашивают: «Почему?»: У меня есть виртуальный метод, который возвращает IList (или, скорее, пост-ответы, в IEnumerable), и реализация по умолчанию является пустым. Независимо от того, что возвращает список, нужно читать только потому, что писать на него будет ошибкой, и если кто-то попытается, я хочу немедленно остановить и поймать огонь, вместо того, чтобы ждать появления ошибки каким-то тонким способом позже.

+4

Что вы будете делать с пустым списком чтения так или иначе? Просто любопытно. – goenning

+0

Я предполагаю, что пустой 'IEnumerable ', вероятно, правильный ответ здесь - действительно нужен IList ? или просто пустую коллекцию только для чтения? –

+1

просто любопытно, зачем вам нужен пустой список только для чтения? –

ответ

18

Лично я считаю, что это лучше, чем любой из других ответов:

static readonly IList<T> EmptyList = new T[0]; 
  • Массивы реализации IList<T>.
  • Вы не можете добавить в массив.
  • Вы не можете назначить элемент в пустом массиве (потому что is none).
  • Это, на мой взгляд, намного проще, чем new List<T>().AsReadOnly().
  • Вы по-прежнему можете вернуть IList<T> (если хотите).

Кстати, это то, что Enumerable.Empty<T>() действительно использует под капотом, если я правильно помню. Поэтому теоретически вы могли бы даже сделать (IList<T>)Enumerable.Empty<T>() (хотя я не вижу причин для этого).

+0

Ваш ответ действительно имеет смысл только в терминах комментариев, прилагаемых к [отвечу Virtlink] (https://stackoverflow.com/a/10659068/712526). – jpaugh

+1

Начиная с версии 4.6 вам больше не нужно предоставлять свой собственный объект, просто верните Array.Empty (). – ZunTzu

21

Вы можете просто создать список:

List<MyType> list = new List<MyType>(); 

Если вы хотите пустой IEnumerable<T>, используйте Enumerable.Empty<T>():

IEnumerable<MyType> collection = Enumerable.Empty<MyType>(); 

Если вы действительно хотите только для чтения список, вы могли бы сделать:

IList<MyType> readonlyList = (new List<MyType>()).AsReadOnly(); 

Это возвращает ReadOnlyCollection<T>, который реализует IList<T>.

+2

Я тоже думал об этом, но потом увидел требование для чтения. Тогда я подумал, что будет точкой пустого списка только для чтения . Что мне не хватает? –

+0

На самом деле нет «только для чтения» Список '... –

+0

@Jay: Я тоже добавил эту опцию ... –

7
IList<T> list = new List<T>().AsReadOnly(); 

Или, если вы хотите, чтобы IEnumerable<>:

IEnumerable<T> sequence = Enumerable.Empty<T>(); 
+1

Начиная с версии 4.6, существует лучшее решение: IList list = Array.Empty (); – ZunTzu

-1

насчет:

readonly List<T> mylist = new List<T>(); 

Не знаю, почему вы хотите это только для чтения; это не имеет большого смысла в большинстве сценариев, о которых я могу думать.

+2

Кроме того, это не делает список доступным только для чтения. – Timwi

+0

Re: почему, см. Отредактированный вопрос выше. –

4

Если вы хотите получить список, содержимое которого не может быть изменен, вы можете сделать:

ReadOnlyCollection<Foo> foos = new List<Foo>().AsReadOnly(); 
2

Чтобы развернуть на Dan Tao's answer, следующая реализация может использоваться так же, как Enumerable.Empty<T>(), указав вместо этого List.Empty<T>().

public static class List 
{ 
    public static IList<T> Empty<T>() 
    { 
     // Note that the static type is only instantiated when 
     // it is needed, and only then is the T[0] object created, once. 
     return EmptyArray<T>.Instance; 
    } 

    private sealed class EmptyArray<T> 
    { 
     public static readonly T[] Instance = new T[0]; 
    } 
} 

Edit: изменить код выше, чтобы отразить результаты обсуждения с Дэн Tao о ленивых против нетерпеливой инициализации Instance поля.

+0

Ленивая инициализация массива нулевой длины? Я лично считаю, что это ошибка, так как она добавляет сложности, сделает производительность немного хуже (дополнительный вызов метода при каждом доступе), имеет условие гонки (два потока, вызывающие «List.Empty ()», в то же время могут иметь разные объекты) и вы почти ничего не покупаете (как вы думаете, стоимость инициализации одного массива нулевой длины сравнивается с стоимостью JIT, компилирующей новый класс?). Идите с нетерпением-инициализированным публичным полем «static readonly», или - если ваша совесть не позволит это - частное поле плюс метод «Пустой». Только мои два цента! –

+1

Две темы, связанные с разными объектами, не являются проблемой. Выполнение не затрагивается, так как вызов [очень вероятно, вложенный] (https://blogs.msdn.com/b/ericgu/archive/2004/01/29/64717.aspx). Я не вижу, как одна строка фактической логики может значительно усложнить сложность. И последнее, но не менее важное: я просто проверил реализацию 'Enumerable.Empty ()' и очень похож на то, что я написал.Если вам нужны пустые списки всех типов повсюду, используйте этот подход, поскольку он сохраняет распределения и мусор. Если вам редко нужен пустой список, используйте 'static readonly'. – Virtlink

+0

Возможно, вы правы, чтобы защищаться, так как мои комментарии, несомненно, расщепляли волосы. Однако разные объекты могут быть проблемой, если, например, у вас был критический код, зависящий от проверки 'if (list == List.Empty ())'. Кроме того, как этот подход экономится на распределениях и мусоре? –

6

Начиная с .net 4.6 вы также можете использовать:

IList<T> emptyList = Array.Empty<T>(); 

Это только создает новый экземпляр один раз для каждого другого типа вы определяете, как Т.

+0

Как и String.Empty, который также всегда ссылается на один и тот же экземпляр вместо создания пустой пустой строки. –

+0

@David De Sloovere пустой литерал строки "" также ссылается на один и тот же экземпляр благодаря интернатуре строк (просто для читателей, которые будут чувствовать себя обязанными заменить "" на String.Empty). – ZunTzu

Смежные вопросы