С#: Разница между 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>?

Ответ 1

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

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

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

Ответ 2

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

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

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