Сведения о вопросе

Fedya

13:05, 8th August, 2020

Теги

Список или BusinessObjectCollection?

Просмотров: 458   Ответов: 18

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

IE:

public class CollectionBase : IEnumerable

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

public class BusinessObjectCollection : CollectionBase

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

public class BusinessObjectCollection : List<BusinessObject>

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

Каков ваш подход?



  Сведения об ответе

pumpa

06:07, 16th August, 2020

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

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

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

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

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

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> напрямую.


  Сведения об ответе

SKY

10:03, 24th August, 2020

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

Но если ты наследуешь от него, то все должно быть в порядке, афаик.


  Сведения об ответе

fo_I_K

16:30, 6th August, 2020

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

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


  Сведения об ответе

LIZA

10:51, 13th August, 2020

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

public class BusinessObjectCollection : List<BusinessObject> {}

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

public IEnumerable<BusinessObject> GetBusinessObjects();

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


  Сведения об ответе

ASER

21:37, 28th August, 2020

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

Там, где вы хотите "add custom code" к списку, методы расширения кода на типе списка. Опять же, приложите эти методы к самому слабому возможному контракту, например:

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

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


  Сведения об ответе

KOMP

01:33, 9th August, 2020

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

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


  Сведения об ответе

DAAA

10:44, 17th August, 2020

Обычно я получаю свои собственные классы коллекций только в том случае, если мне нужно "add value". Например, если сама коллекция должна иметь некоторые свойства "metadata", помеченные вместе с ней.


  Сведения об ответе

davran

23:44, 9th August, 2020

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


  Сведения об ответе

davran

22:59, 18th August, 2020

Вы можете использовать и то, и другое. Для лени - я имею в виду продуктивность-список является очень полезным классом, он также "comprehensive" и откровенно полон YANGNI членов. В сочетании с разумным аргументом / рекомендацией, выдвинутым в статье MSDN , уже связанной с выставлением списка в качестве публичного члена, я предпочитаю путь "third":

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

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 или more likley для perf использовать коллекцию или набор пар значений ключей.


  Сведения об ответе

KOMP

15:56, 20th August, 2020

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


  Сведения об ответе

SKY

18:57, 2nd August, 2020

6 из 1, полдюжины других

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

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


  Сведения об ответе

lourence

03:42, 12th August, 2020

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

public MyTypeCollection : List<MyType>

В большинстве случаев public APIs будет выставлять IList (или ICollection, или IEnumerable) соответственно.

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


  Сведения об ответе

qwerty101

04:14, 23rd August, 2020

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

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


  Сведения об ответе

LIZA

03:47, 25th August, 2020

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

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


  Сведения об ответе

LAST

21:06, 1st October, 2020

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


  Сведения об ответе

+-*/

03:17, 13th August, 2020

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

System.Collections.ObjectModel.Collection<BusinessObject>

это делает ненужным реализацию базового метода, как CollectionBase do


  Сведения об ответе

fo_I_K

02:54, 26th August, 2020

Я бы так и сделал:

using BusinessObjectCollection = List<BusinessObject>;

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


  Сведения об ответе

nYU

12:15, 11th August, 2020

это и есть путь:

возвращаем массивы, принимаем IEnumerable<T>

=)


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться