List czy BusinessObjectCollection?

Przed C# generics, każdy kodował kolekcje dla swoich obiektów biznesowych, tworząc bazę kolekcji, która zaimplementowała IEnumerable

IE:

public class CollectionBase : IEnumerable

A następnie wyprowadzają z tego swoje zbiory obiektów biznesowych.

public class BusinessObjectCollection : CollectionBase

Teraz z klasy generic list, czy ktoś po prostu używać tego zamiast? Odkryłem, że używam kompromisu dwóch technik:

public class BusinessObjectCollection : List<BusinessObject>

Robię to, ponieważ lubię mocno wpisywać nazwy zamiast tylko wymieniać listy w pobliżu.

Jakie jest twoje podejście?

Author: Mark Biek, 2008-08-22

18 answers

Generalnie jestem w obozie po prostu używać listy bezpośrednio, chyba że z jakiegoś powodu muszę enkapsulować strukturę danych i zapewnić Ograniczony podzbiór jej funkcjonalności. Dzieje się tak głównie dlatego, że jeśli nie mam konkretnej potrzeby enkapsulacji, to robienie tego jest tylko stratą czasu.

Jednakże, z funkcją aggregate initializes w C# 3.0, są pewne nowe sytuacje, w których zalecałbym używanie niestandardowych klas kolekcji.

Zasadniczo C # 3.0 pozwala na dowolne klasa, która implementuje IEnumerable i ma metodę Add, aby użyć nowej składni inicjalizatora agregującego. Na przykład, ponieważ Słownik definiuje metodę Add (klucz K, wartość V), możliwe jest zainicjowanie słownika za pomocą tej składni:

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

Wspaniałą cechą tej funkcji jest to, że działa ona dla metod dodawania z dowolną liczbą argumentów. Na przykład, biorąc pod uwagę ten zbiór:

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

    //...
}

Możliwe byłoby zainicjowanie go w ten sposób:

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

To może być naprawdę przydatne, jeśli potrzeba tworzenia statycznych tabel złożonych obiektów. Na przykład, jeśli używasz List<Customer> i chcesz utworzyć statyczną listę obiektów klienta, musisz utworzyć ją w następujący sposób:

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")
}

Jednak, jeśli używasz niestandardowej kolekcji, takiej jak ta:

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

Możesz zainicjować kolekcję używając tej składni:

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"}
}

Ma tę zaletę, że jest zarówno łatwiejsze do wpisania, jak i łatwiejsze do odczytania, ponieważ nie ma potrzeby ponownego wpisywania nazwy typu elementu dla każdy element. Zaleta może być szczególnie silna, jeśli Typ elementu jest długi lub złożony.

To powiedziawszy, jest to przydatne tylko wtedy, gdy potrzebujesz statycznych zbiorów danych zdefiniowanych w aplikacji. Niektóre typy aplikacji, takie jak kompilatory, używają ich cały czas. Inne, takie jak Typowe aplikacje bazodanowe, nie robią tego, ponieważ ładują wszystkie swoje dane z bazy danych.

Moja rada byłaby taka, że jeśli albo trzeba zdefiniować statyczny zbiór obiektów, albo trzeba zamknąć zbiór interfejs, a następnie utwórz własną klasę kolekcji. W przeciwnym razie użyłbym List<T> bezpośrednio.

 49
Author: Scott Wisniewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-17 17:49:58

Jest zalecane aby w publicznym API nie używać List, ale używać Collection

Jeśli jednak dziedziczysz po nim, powinieneś być w porządku, afaik.

 14
Author: Darren Kopp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:39:05

Wolę po prostu używać List<BusinessObject>. Wpisując to dodajemy do kodu zbędny boilerplate. List<BusinessObject> jest specyficznym typem, nie jest to zwykły obiekt List, więc nadal jest mocno wpisany.

Co ważniejsze, deklarowanie czegoś List<BusinessObject> ułatwia każdemu czytającemu kod określenie, z jakimi typami ma do czynienia, nie musi przeszukiwać, aby dowiedzieć się, czym jest BusinessObjectCollection, a następnie pamiętać, że to tylko lista. Wpisując, będziesz musiał wymagać spójnego (ponownego)nazewnictwa konwencja, którą każdy musi przestrzegać, aby miała sens.

 9
Author: tghw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:34:18

Użyj typu List<BusinessObject> gdzie musisz zadeklarować ich listę. Jednakże, jeśli zwrócisz listę BusinessObject, rozważ zwrócenie IEnumerable<T>, IList<T> lub ReadOnlyCollection<T> - tj. zwróć najsłabszą możliwą umowę, która zadowoli klienta.

Jeśli chcesz "dodać kod niestandardowy" do listy, koduj metody rozszerzenia w typie listy. Ponownie Dołącz te metody do najsłabszego możliwego kontraktu, np.

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

Oczywiście nie można i nie należy dodawać stanu za pomocą metod extension, więc jeśli trzeba dodać Nowa właściwość i pole za nią, użyj podklasy lub lepszej, klasy wrapper, aby to zapisać.

 4
Author: Anthony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-27 14:52:24

I ' ve been back and back on 2 options:

public class BusinessObjectCollection : List<BusinessObject> {}

Lub metody, które po prostu wykonują następujące czynności:

public IEnumerable<BusinessObject> GetBusinessObjects();

Korzyści z pierwszego podejścia polega na tym, że można zmienić bazowy magazyn danych bez konieczności bałaganu z podpisami metod. Niestety, jeśli dziedziczysz po typie kolekcji, który usuwa metodę z poprzedniej implementacji, będziesz musiał radzić sobie z tymi sytuacjami w całym kodzie.

 4
Author: Scott Muc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-17 01:14:00

Prawdopodobnie powinieneś unikać tworzenia własnej kolekcji w tym celu. Często zdarza się, że podczas refaktoryzacji lub dodawania nowych funkcji kilka razy chcemy zmienić typ struktury danych. Z twoim podejściem skończysz z oddzielną klasą dla BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree itp.

Naprawdę nie widzę żadnej wartości w tworzeniu tej klasy tylko dlatego, że nazwa klasy jest bardziej czytelna. Tak, składnia wspornika kątowego jest trochę brzydka, ale jest to standard w C++, C# i Javie, więc nawet jeśli nie napiszesz kodu, który go używa, będziesz na niego ciągle wpadał.

 3
Author: Outlaw Programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:35:09

Robię dokładnie to samo co Ty Jonathan... po prostu Dziedzicz od List<T>. Dostajesz to, co najlepsze z obu światów. Ale generalnie robię to tylko wtedy, gdy jest jakaś wartość do dodania, jak dodanie metody LoadAll() czy cokolwiek innego.

 3
Author: jeremcc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:40:26

Zazwyczaj wyprowadzam własne klasy kolekcji tylko wtedy, gdy muszę "dodać wartość". Na przykład, jeśli sama kolekcja musi mieć pewne właściwości" metadane " tagowania wraz z nim.

 2
Author: Matt Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:28:35

Możesz użyć obu. Dla lenistwa - mam na myśli produktywność-lista jest bardzo przydatną klasą, jest też "obszerna" i szczerze mówiąc pełna członków YANGNI. W połączeniu z sensownym argumentem / rekomendacją przedstawionym przez artykuł MSDN już linkowany o ujawnianiu listy jako członka publicznego, wolę "trzeci" sposób:

Osobiście używam wzoru dekoratora, aby odsłonić tylko to, czego potrzebuję z listy TJ:

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();
    }    
}

Dalej jeszcze pewnie bym abstrakcyjny uporządkował IOrderItemCollection więc mogę zamienić moją implementację IOrderItemCollection na w przyszłości w (mogę preferować użycie innego wewnętrznego obiektu enumerable, takiego jak Collection lub bardziej likley dla perf użyj kolekcji pary wartości klucza lub zestawu.

 2
Author: Ed Blackburn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-27 14:07:59

Używam list generycznych dla prawie wszystkich scenariuszy. Jedyny czas, w którym rozważyłbym użycie kolekcji pochodnej, to dodanie konkretnych członków kolekcji. Jednak pojawienie się LINQ zmniejszyło potrzebę nawet tego.

 1
Author: Ryan Eastabrook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 05:02:08

6 of 1, half tuzin of another

Tak czy siak to to samo. Robię to tylko wtedy, gdy mam powód, aby dodać niestandardowy kod do BusinessObjectCollection.

Bez tego, że metody ładowania zwracają listę, pozwala mi napisać więcej kodu we wspólnej klasie generycznej i mieć go po prostu działającego. Takie jak Metoda ładowania.

 0
Author: AdamSane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 03:33:17

Jak ktoś inny zauważył, zaleca się nie ujawniać listy publicznie, a FxCop będzie jęczeć, jeśli to zrobisz. Dotyczy to dziedziczenia z listy jak w:

public MyTypeCollection : List<MyType>

W większości przypadków publiczne API ujawniają IList (lub Collection lub IEnumerable) odpowiednio.

W przypadkach, gdy chcesz mieć własną kolekcję niestandardową, możesz zachować FxCop w tajemnicy, dziedzicząc z kolekcji zamiast z listy.

 0
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 18:15:57

Jeśli zdecydujesz się stworzyć własną klasę kolekcji powinieneś sprawdzić typy w systemie .Kolekcje.ObjectModel Namespace .

Przestrzeń nazw definiuje klasy bazowe, które mają ułatwić implementatorom tworzenie własnych kolekcji.

 0
Author: Hallgrim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 16:05:46

Zazwyczaj robię to z własną kolekcją, jeśli chcę zabezpieczyć dostęp do rzeczywistej listy. Kiedy piszesz obiekty biznesowe, szansa jest taka, że potrzebujesz Hooka, aby wiedzieć, czy twój obiekt jest dodawany/usuwany, w takim sensie myślę, że BOCollection jest lepszym pomysłem. Bo jeśli nie jest to wymagane, lista jest bardziej lekka. Możesz również sprawdzić użycie IList, aby zapewnić dodatkowy interfejs abstrakcji, jeśli potrzebujesz jakiegoś proxyingu (np. fałszywa kolekcja wyzwala leniwe ładowanie z baza danych)

Ale... dlaczego nie wziąć pod uwagę Castle ActiveRecord lub jakiegokolwiek innego dojrzałego frameworka ORM? :)

 0
Author: William Yeung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 16:11:12

W większości przypadków po prostu wybieram sposób listy, ponieważ daje mi ona wszystkie funkcje, których potrzebuję w 90% czasu, a gdy potrzebne jest coś "ekstra", dziedziczę z niego i koduję ten dodatkowy bit.

 0
Author: Adam Vigh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 16:13:08

Zrobiłbym to:

using BusinessObjectCollection = List<BusinessObject>;

To po prostu tworzy alias, a nie zupełnie nowy typ. Wolę używać List bezpośrednio, ponieważ pozostawia mi to swobodę zmiany podstawowej struktury kolekcji w pewnym momencie w przyszłości bez zmiany kodu, który go używa (o ile podam te same właściwości i metody).

 0
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 16:07:09

Wypróbuj to:

System.Collections.ObjectModel.Collection<BusinessObject>

Nie jest konieczne implementowanie podstawowej metody, takiej jak CollectionBase do

 0
Author: abatishchev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-27 09:45:11

Oto sposób:

Return arrays, accept IEnumerable<T>

=)

 -1
Author: Matt Hinze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 03:20:19