C #: Разница между List ‹T› и Collection ‹T› (CA1002, Не раскрывать общие списки)

Пытался запустить анализ кода для проекта здесь, и получил ряд предупреждений, в которых говорилось что-то вроде этого:

CA1002: Microsoft.Design: измените 'List ‹SomeType>' в 'SomeClass.SomeProtectedOrPublicProperty', чтобы использовать Collection, ReadOnlyCollection или KeyedCollection

Почему я должен использовать Collection<T> вместо List<T>? Когда я смотрю документацию msdn, они кажутся почти равными. Прочитав справку по ошибке для предупреждения, я обнаружил, что

System.Collections.Generic.List (T) _ - это универсальная коллекция, предназначенная для производительности, а не наследования, и, следовательно, не содержит никаких виртуальных членов.

Но что это на самом деле означает? И что мне делать вместо этого?

Должен ли я продолжать использовать List<T> для внутренних целей, а затем вместо этого в свойствах возвращать new Collection<T>(someList)? Или мне просто начать использовать Collection<T> вместо List<T>?


person Svish    schedule 05.08.2009    source источник
comment
Подробное объяснение см. В этом сообщении в блоге.   -  person Thomas Levesque    schedule 05.08.2009
comment
Кстати, если вы хотите знать, почему Коллекция находится в System.Collections .ObjectModel затем прочтите это Кшиштофа Квалины.   -  person Dan Diplo    schedule 05.08.2009
comment
Ссылка @ ThomasLevesque теперь не работает, но сообщение в блоге теперь доступно здесь: blogs.msdn.microsoft.com/codeanalysis/2006/04/27/   -  person Ben Randall    schedule 26.03.2018
comment
Ссылка Дэна тоже не работает. История ObjectModel теперь здесь: docs.microsoft.com/en-us/archive/blogs/kcwalina/   -  person Arthur Ward    schedule 12.06.2020


Ответы (2)


Короче говоря, общий список не имеет виртуальных методов для добавления, удаления и т. Д., Поскольку он был разработан, чтобы быть быстрым, а не расширяемым. Это означает, что вы не можете поменять эту конкретную реализацию на полезный подкласс (даже если вы можете создать подкласс, поскольку он не запечатан).

Следовательно, открывая сам список, вы никогда не сможете расширить свою коллекцию для отслеживания операций добавления или удаления (например) без нарушения публичного контракта класса.

Выставляя свою коллекцию как IList или что-то в этом роде, вы все равно можете использовать List в качестве фактического резервного хранилища, но при этом сохраняете будущую расширяемость, поскольку вы можете заменить реализацию Concerete позже, не изменяя публичный контракт вашего класса.

person Rob Levine    schedule 05.08.2009
comment
К вашему сведению, Collection<T> использует экземпляр List<T> внутри. - person Zoltán Tamási; 10.09.2015

Collection предоставляет некоторые виртуальные члены (вставка, удаление, установка, очистка), которые вы можете переопределить и предоставить дополнительные функции (например, события уведомления) при изменении коллекции.

Возможно, сейчас вам это не понадобится, но это обычное требование для классов, содержащих коллекции, поэтому лучше спланировать это заранее. Поскольку Collection разработан с учетом расширяемости, он очень гибкий. Если в будущем вы решите, что вам понадобится какая-то дополнительная функция в коллекции, вы можете просто расширить ее без каких-либо изменений в общедоступном интерфейсе класса. Если бы вы использовали список, вам пришлось бы изменить его на коллекцию, что означает, что он сломал бы все вызывающие объекты вашего класса, потому что их нужно было бы изменить, чтобы использовать списки.

List, с другой стороны, разработан с учетом производительности, поэтому должен использоваться только в особых случаях, когда производительность очень важна. Поскольку это не расширяемое, будущие изменения чего-либо с использованием списка сломают все остальное, зависящее от него. Обычно List следует использовать только внутри классов очень низкого уровня и не подвергать никакому воздействию, чтобы уменьшить вероятность будущих критических изменений.

person Simon P Stevens    schedule 05.08.2009