Intereting Posts
Извлечение фабрики COM-classа для компонента с CLSID не удалось из-за следующей ошибки: 80070005 Отказано в доступе Как включить «Обозреватель объектов» в «Метаданные» для «Перейти к определению» в Visual Studio 2010? Ограничение API для ограничения скорости обмена Преобразование результата совпадений из регулярного выражения в список строк .NET Core Entity Framework – добавление переноса для контекста в библиотеке classов Обновить свойство ReadOnly во время EventsPublishedContent Лучший способ ограничить десятичный ввод текстового поля в c # как отображать имя пользователя в элементе управления именным именем Как добавить функции поиска и позиции в CryptoStream Как не копировать файл app.config в выходной каталог Разбор математического выражения PSD для WPF XAML: импорт испорчен Насколько дорогой список.RemoveAt (0) для общего списка? Оператор ‘==’ не может применяться к операндам типа ‘char’ и ‘string’ Можете ли вы расширить свойства HttpContext.Current.User.Identity

C #: инкапсуляция, например, коллекций

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

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

Пример 1

class Bus { public IEnumerable Passengers { get { return passengers; } } private List passengers; public Bus() { passengers = new List(); } public void AddPassenger(Passenger passenger) { passengers.Add(passenger); } } var bus = new Bus1(); bus.AddPassenger(new Passenger()); foreach(var passenger in bus.Passengers) Console.WriteLine(passenger); 

Пример 2.

 class Bus { public List Passengers { get; private set; } public Bus() { Passengers = new List(); } } var bus = new Bus(); bus.Passengers.Add(new Passenger()); foreach(var passenger in bus.Passengers) Console.WriteLine(passenger); 

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

В примере один можно изменить вашу коллекцию.

Рассмотрим следующее:

 var passengers = (List)bus.Passengers; // Now I have control of the list! passengers.Add(...); passengers.Remove(...); 

Чтобы исправить это, вы можете рассмотреть что-то вроде этого:

 class Bus { private List passengers; // Never expose the original collection public IEnumerable Passengers { get { return passengers.Select(p => p); } } // Or expose the original collection as read only public ReadOnlyCollection ReadOnlyPassengers { get { return passengers.AsReadOnly(); } } public void AddPassenger(Passenger passenger) { passengers.Add(passenger); } } 

В большинстве случаев я бы рассмотрел пример 2, чтобы быть приемлемым при условии, что базовый тип был расширяемым и / или раскрывал некоторые формы событий onAdded / onRemoved, чтобы ваш внутренний class мог реагировать на любые изменения в коллекции.

В этом случае List не подходит, так как нет возможности узнать, что что-то добавлено. Вместо этого вы должны использовать коллекцию, потому что class Collection имеет несколько виртуальных членов (Insert, Remove, Set, Clear), которые можно переопределить, а триггеры событий добавлены, чтобы уведомить class обертки.

(Вы также должны знать, что пользователи classа могут изменять элементы в списке / коллекции, не зная об этом родительский class, поэтому убедитесь, что вы не полагаетесь на неизменные элементы – если они не являются неизменными, очевидно – или вы можете предоставить события стиля «Стиль», если вам нужно.)

Запустите соответствующие примеры через FxCop, и это должно дать вам подсказку о рисках, связанных с отображением List

Я бы сказал, что все сводится к вашей ситуации. Я бы обычно пошел на вариант 2, поскольку он является самым простым, если у вас нет оснований для бизнеса, чтобы добавить к нему более жесткие элементы управления.

Вариант 2 является самым простым, но позволяет другим classам добавлять / удалять элементы коллекции, что может быть опасно.

Я думаю, что хорошая эвристика – это рассмотреть, что делают методы обертки. Если ваш метод AddPassenger (или Удалить или другие) просто передает вызов коллекции, я бы пошел на более простую версию. Если вам нужно проверить элементы перед их вставкой, то вариант 1 в принципе неизбежен. Если вам нужно отслеживать вставленные / удаленные элементы, вы можете пойти в любом случае. С помощью опции 2 вам необходимо зарегистрировать события в коллекции, чтобы получать уведомления, а с помощью опции 1 вам нужно создать обертку для каждой операции в списке, который вы хотите использовать (например, если вы хотите Вставить, а также Добавить), поэтому я предполагаю это зависит.