Вопрос

До появления дженериков C# каждый кодировал коллекции для своих бизнес-объектов, создавая базу коллекций, реализующую IEnumerable.

ИЕ:

public class CollectionBase : IEnumerable

а затем получали из этого свои коллекции бизнес-объектов.

public class BusinessObjectCollection : CollectionBase

Теперь, когда есть общий класс списка, кто-нибудь вместо этого использует его?Я обнаружил, что использую компромисс двух методов:

public class BusinessObjectCollection : List<BusinessObject>

Я делаю это, потому что мне нравится иметь строго типизированные имена, а не просто передавать списки.

Что твой подход?

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

Решение

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

Однако благодаря функции агрегатной инициализации в C# 3.0 возникают новые ситуации, в которых я бы рекомендовал использовать настраиваемые классы коллекций.

По сути, C# 3.0 допускает любой класс, реализующий IEnumerable и имеет метод Add для использования нового синтаксиса агрегатного инициализатора.Например, поскольку словарь определяет метод Add(ключ K, значение V), словарь можно инициализировать, используя следующий синтаксис:

var d = new Dictionary<string, int>
{
    {"hello", 0},
    {"the answer to life the universe and everything is:", 42}
};

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

class c1 : IEnumerable
{
    void Add(int x1, int x2, int x3)
    {
        //...
    }

    //...
}

можно было бы инициализировать его так:

var x = new c1
{
    {1,2,3},
    {4,5,6}
}

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

var x = new List<Customer>
{
    new Customer("Scott Wisniewski", "555-555-5555", "Seattle", "WA"),
    new Customer("John Doe", "555-555-1234", "Los Angeles", "CA"),
    new Customer("Michael Scott", "555-555-8769", "Scranton PA"),
    new Customer("Ali G", "", "Staines", "UK")
}

Однако, если вы используете настроенную коллекцию, например эту:

class CustomerList  : List<Customer>
{
    public void Add(string name, string phoneNumber, string city, string stateOrCountry)
    {
        Add(new Customer(name, phoneNumber, city, stateOrCounter));
    }
}

Затем вы можете инициализировать коллекцию, используя этот синтаксис:

var customers = new CustomerList
{
    {"Scott Wisniewski", "555-555-5555", "Seattle", "WA"},
    {"John Doe", "555-555-1234", "Los Angeles", "CA"},
    {"Michael Scott", "555-555-8769", "Scranton PA"},
    {"Ali G", "", "Staines", "UK"}
}

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

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

Мой совет: если вам нужно определить статическую коллекцию объектов или инкапсулировать интерфейс коллекции, создайте собственный класс коллекции.В противном случае я бы просто использовал List<T> напрямую.

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

Его рекомендуемые что в общедоступном API не следует использовать List<T>, а использовать Collection<T>

Однако если вы наследуете от него, с вами все будет в порядке, афаик.

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

Что еще более важно, объявив что-то List<BusinessObject> облегчает каждому, кто читает код, понять, с какими типами они имеют дело, им не нужно искать, чтобы выяснить, с какими типами BusinessObjectCollection есть, а затем помните, что это всего лишь список.При определении типов вам придется потребовать согласованного соглашения о переименовании, которому все должны следовать, чтобы оно имело смысл.

Используйте тип List<BusinessObject> где вам нужно объявить их список.Однако, где вы возвращаете список BusinessObject, подумайте о возврате IEnumerable<T>, IList<T> или ReadOnlyCollection<T> - т.е.вернуть самый слабый возможный контракт, удовлетворяющий клиента.

Если вы хотите «добавить собственный код» в список, используйте методы расширения кода для типа списка.Опять же, прикрепите эти методы к самому слабому контракту, например.

public static int SomeCount(this IEnumerable<BusinessObject> someList)

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

Я обдумывал 2 варианта:

public class BusinessObjectCollection : List<BusinessObject> {}

или методы, которые просто делают следующее:

public IEnumerable<BusinessObject> GetBusinessObjects();

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

Вероятно, вам следует избегать создания собственной коллекции для этой цели.Довольно часто возникает желание изменить тип структуры данных несколько раз во время рефакторинга или при добавлении новых функций.При вашем подходе вы получите отдельный класс для BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree и т. д.

Я не вижу никакой ценности в создании этого класса только потому, что имя класса более читабельно.Да, синтаксис угловых скобок довольно уродлив, но он стандартен для C++, C# и Java, поэтому даже если вы не пишете код, использующий его, вы будете сталкиваться с ним постоянно.

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

Я делаю то же самое, что и ты, Джонатан...просто наследовать от List<T>.Вы получаете лучшее из обоих миров.Но обычно я делаю это только тогда, когда есть что-то, что можно добавить, например, добавление LoadAll() метод или что-то еще.

Вы можете использовать оба.Что касается лени — я имею в виду производительность — List — очень полезный класс, он также «всеобъемлющий» и, откровенно говоря, полон членов YANGNI.В сочетании с разумным аргументом/рекомендацией, выдвинутой Статья MSDN уже упоминалось о разоблачении Листа как публичного члена, я предпочитаю «третий» способ:

Лично я использую шаблон декоратора, чтобы отображать из списка только то, что мне нужно, т.е.:

public OrderItemCollection : IEnumerable<OrderItem> 
{
    private readonly List<OrderItem> _orderItems = new List<OrderItem>();

    void Add(OrderItem item)
    {
         _orderItems.Add(item)
    }

    //implement only the list members, which are required from your domain. 
    //ie. sum items, calculate weight etc...

    private IEnumerator<string> Enumerator() {
        return _orderItems.GetEnumerator();
    }

    public IEnumerator<string> GetEnumerator() {
        return Enumerator();
    }    
}

Кроме того, я бы, вероятно, абстрагировал OrderItemCollection в IOrderItemCollection, чтобы я мог поменять свою реализацию IOrderItemCollection в будущем (я могу предпочесть использовать другой внутренний перечислимый объект, такой как Collection или, что более вероятно, для производительности, используйте коллекцию пар ключевых значений или набор .

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

6 из 1, полдюжины еще одного

В любом случае это одно и то же.Я делаю это только тогда, когда у меня есть причина добавить собственный код в BusinessObjectCollection.

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

Как заметил кто-то другой, рекомендуется не публиковать список, и FxCop будет жаловаться, если вы это сделаете.Это включает в себя наследование от List, как в:

public MyTypeCollection : List<MyType>

В большинстве случаев общедоступные API будут предоставлять IList (или ICollection или IEnumerable) по мере необходимости.

В тех случаях, когда вам нужна собственная коллекция, вы можете сохранить FxCop в тайне, наследуя от Collection вместо List.

Если вы решите создать свой собственный класс коллекции, вам следует проверить типы в System.Collections.ObjectModel Пространство имен.

Пространство имен определяет базовые классы, которые созданы для того, чтобы разработчикам было проще создавать собственные коллекции.

Я обычно делаю это со своей собственной коллекцией, если хочу защитить доступ к реальному списку.Когда вы пишете бизнес-объекты, есть вероятность, что вам понадобится ловушка, чтобы узнать, добавляется/удаляется ли ваш объект, в этом смысле я думаю, что BOCollection — лучшая идея.Конечно, если это не требуется, List более легкий.Также вы можете проверить использование IList для предоставления дополнительного интерфейса абстракции, если вам нужен какой-то прокси (например,поддельная коллекция вызывает отложенную загрузку из базы данных)

Но...почему бы не рассмотреть Castle ActiveRecord или любую другую зрелую структуру ORM?:)

В большинстве случаев я просто использую список, поскольку он дает мне всю необходимую функциональность в 90% случаев, а когда требуется что-то «дополнительное», я наследую от него и кодирую этот дополнительный бит. .

Я бы сделал это:

using BusinessObjectCollection = List<BusinessObject>;

Это просто создает псевдоним, а не совершенно новый тип.Я предпочитаю использовать его напрямую, поскольку List<BusinessObject> позволяет мне изменить базовую структуру коллекции в какой-то момент в будущем, не меняя код, который ее использует (при условии, что я предоставляю те же свойства и методы).

попробуйте это:

System.Collections.ObjectModel.Collection<BusinessObject>

нет необходимости реализовывать базовый метод, такой как CollectionBase.

это способ:

вернуть массивы, принять IEnumerable<T>

=)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top