Коллекция<T> сравнение со списком<T> что вы должны использовать в своих интерфейсах?

StackOverflow https://stackoverflow.com/questions/271710

Вопрос

Код выглядит следующим образом:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

Когда я запускаю анализ кода, я получаю следующую рекомендацию.

Предупреждение 3 CA1002 :Майкрософт.Дизайн :Измените 'List' в 'IMyClass.getList()', чтобы использовать Collection, ReadOnlyCollection или KeyedCollection

Как я должен это исправить и какова здесь хорошая практика?

Это было полезно?

Решение

Чтобы ответить на "почему" часть вопроса о том, почему нет List<T>, Причины кроются в перспективности и простоте API.

Защита от воздействия на будущее

List<T> не предназначен для того, чтобы его можно было легко расширять путем создания подкласса;он разработан таким образом, чтобы быть быстрым для внутренних реализаций.Вы заметите, что методы в нем не являются виртуальными и поэтому не могут быть переопределены, и в нем нет перехватов Add/Insert/Remove операции.

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

Таким образом, возвращая либо класс, который можно легко разделить на подклассы, например Collection<T> или интерфейс, такой как IList<T>, ICollection<T> или IEnumerable<T> вы можете изменить свою внутреннюю реализацию на другой тип коллекции в соответствии с вашими потребностями, не нарушая код потребителей, потому что он все равно может быть возвращен как тип, который они ожидают.

Простота API

List<T> содержит множество полезных операций, таких как BinarySearch, Sort и так далее.Однако, если это коллекция, которую вы предоставляете, то, скорее всего, вы контролируете семантику списка, а не потребителей.Таким образом, хотя вашему классу внутренне могут потребоваться эти операции, очень маловероятно, что потребители вашего класса захотят (или даже должны будут) вызвать их.

Таким образом, предлагая более простой класс коллекции или интерфейс, вы сокращаете количество элементов, которые видят пользователи вашего API, и упрощаете его использование.

Другие советы

Я бы лично объявил, что он возвращает интерфейс, а не конкретную коллекцию. Если вы действительно хотите получить доступ к списку, используйте IList < T > . В противном случае рассмотрите ICollection < T > и IEnumerable < T > .

В основном речь идет об абстрагировании ваших собственных реализаций, а не о предоставлении объекта List для прямого манипулирования.

Не рекомендуется позволять другим объектам (или людям) напрямую изменять состояние ваших объектов. Подумайте о свойствах геттеров / сеттеров.

Коллекция - > Для нормальной коллекции
ReadOnlyCollection - > Для коллекций, которые не должны быть изменены
KeyedCollection - > Когда вы хотите словари вместо этого.

Как это исправить, зависит от того, что вы хотите, чтобы ваш класс делал, и от цели метода GetList (). Можете ли вы уточнить?

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

Я не думаю, что кто-то ответил на вопрос "почему" расстаться пока ... так что вот. Причина "почему" Вы "должны" используйте Collection < T > вместо List < T > потому, что если вы выставите List < T > , тогда любой, кто получит доступ к вашему объекту можно изменять элементы в списке. Принимая во внимание, что Collection < T > должен указывать на то, что вы создаете свои собственные методы "Add " ;, " Remove " ;, etc".

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

Если у вас есть открытый массив, например:

public int[] MyIntegers { get; }

Вы могли бы подумать, что это потому, что есть только " get " Accessor, что никто не может связываться со значениями, но это не так. Любой может изменить значения внутри, вот так:

someObject.MyIngegers[3] = 12345;

Лично я бы просто использовал List < T > в большинстве случаев. Но если вы разрабатываете библиотеку классов, которую вы собираетесь раздавать случайным разработчикам, и вам нужно полагаться на состояние объектов ... тогда вы захотите создать свою собственную коллекцию и заблокировать ее оттуда: )

Что-то добавить, хотя прошло много времени с тех пор, как об этом спросили.

Когда ваш тип списка наследуется от List < T > вместо Collection < T > , вы не можете реализовать защищенные виртуальные методы, которые Collection < T > реализует. Это означает, что ваш производный тип не может отвечать в случае внесения каких-либо изменений в список. Это связано с тем, что List < T > предполагает, что вы знаете, когда добавляете или удаляете элементы. Возможность отвечать на уведомления является дополнительной нагрузкой, и поэтому List < T > не предлагает ее.

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

Я не вижу проблем с возвратом чего-то вроде

this.InternalData.Filter(crteria).ToList();

Если я вернул отключенную копию внутренних данных или отсоединенный результат запроса данных - я могу смело возвращать List < TItem > , не раскрывая никаких деталей реализации, и позволяют использовать возвращенные данные удобным способом.

Но это зависит от того, какого типа потребителей я ожидаю - если это что-то вроде сетки данных, я предпочитаю возвращать IEnumerable < TItem > , который будет скопированным списком элементов в любом случае в большинстве случаев:)

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

Думаю, вам не стоит об этом беспокоиться, но если вы действительно хотите угодить инструменту анализа кода, просто сделайте следующее:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top