2008-08-22 4 views
45

Vor C# Generika, würde jede Sammlung für ihre Business-Objekte Code durch eine Sammlung Basis zu schaffen, die IEnumerableListe <BusinessObject> oder BusinessObjectCollection?

IE implementiert:

public class CollectionBase : IEnumerable 

und dann ihre Business Object Sammlungen aus, dass zuzustünden.

Jetzt mit der generischen Liste Klasse, verwendet jemand stattdessen stattdessen? Ich habe festgestellt, dass ich einen Kompromiss der beiden Techniken verwenden:

public class BusinessObjectCollection : List<BusinessObject> 

ich dies tun, weil ich stattdessen stark typisierte Namen haben möchte nur um Listen vorbei.

Was ist Ihr Ansatz?

Antwort

49

Ich bin im Allgemeinen im Lager nur eine Liste direkt verwenden, es sei denn, aus irgendeinem Grunde Ich brauche die Datenstruktur zu verkapseln und eine begrenzte Teilmenge der Funktionalität. Dies liegt vor allem daran, dass es keine Zeitverschwendung ist, wenn ich kein spezifisches Bedürfnis nach Verkapselung habe.

Doch mit dem Aggregat initialisiert Funktion in C# 3.0, gibt es einige neue Situationen, in denen ich befürworten würde Ihre eigene Sammlung Klassen.

Grundsätzlich ermöglicht C# 3.0 jede Klasse, die IEnumerable implementiert und über eine Add-Methode verfügt, um die neue Aggregatinitialisierungssyntax zu verwenden. Zum Beispiel, weil Wörterbuch eine Methode Add (K-Taste, V-Wert) definiert ist es möglich, ein Wörterbuch mit folgenden Syntax zu initialisieren:

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

Die große Sache über das Merkmal ist, dass es für Add-Methoden mit einem beliebigen Anzahl funktioniert von Argumenten. Zum Beispiel dieser Sammlung gegeben:

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

    //... 
} 

es möglich wäre, es zu initialisieren, etwa so:

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

Dies kann sehr nützlich sein, wenn Sie statische Tabellen komplexer Objekte erstellen müssen. wenn Sie nur Zum Beispiel wurden List<Customer> verwenden und Sie wollten eine statische Liste von Kundenobjekten erstellen würden Sie es wie so erstellen müssen:

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

Wenn Sie jedoch eine individuelle Sammlung verwenden, wie diese:

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

Sie könnten dann initialisieren die Sammlung mit folgenden Syntax:

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

Dies hat den Vorteil, die beide leichter zu schreiben und leichter zu lesen weil sie den Elementtypnamen für jedes Element nicht erneut eingeben müssen. Der Vorteil kann besonders stark sein, wenn der Elementtyp lang oder komplex ist.

Davon abgesehen, ist dies nur dann sinnvoll, wenn Sie statische Sammlungen von Daten definiert in Ihrer Anwendung benötigen. Einige Arten von Apps, wie Compiler, verwenden sie ständig. Andere, wie typische Datenbank-Apps, tun dies nicht, weil sie alle ihre Daten aus einer Datenbank laden.

Mein Rat wäre, dass, wenn Sie entweder eine statische Sammlung von Objekten definieren, oder müssen die Sammlung Schnittstelle verkapseln weg, dann eine benutzerdefinierte Auflistungsklasse erstellen.Ansonsten würde ich einfach List<T> direkt verwenden.

2

Ich leite in der Regel nur meine eigenen Collection-Klassen ab, wenn ich "Wert hinzufügen" muss. Zum Beispiel, wenn die Sammlung selbst einige "Metadaten" -Eigenschaften haben müsste, die mit ihr taggen.

4

Ich habe hin und her auf 2 Möglichkeiten gegangen:

public class BusinessObjectCollection : List<BusinessObject> {} 

oder Methoden, die nur Folgendes tun:

public IEnumerable<BusinessObject> GetBusinessObjects(); 

Die Vorteile des ersten Ansatzes ist, dass Sie das ändern können darunterliegenden Datenspeicher, ohne sich mit Methodensignaturen herumschlagen zu müssen. Wenn Sie jedoch von einem Auflistungstyp erben, der eine Methode aus der vorherigen Implementierung entfernt, müssen Sie sich mit diesen Situationen im gesamten Code befassen.

3

Ich mache genau das gleiche wie Sie Jonathan ... nur erben von List<T>. Sie erhalten das Beste aus beiden Welten. Aber ich mache es im Allgemeinen nur, wenn ein Wert hinzugefügt werden muss, wie zum Beispiel das Hinzufügen einer LoadAll() Methode oder was auch immer.

+0

Sie könnten LoadAll() als eine Erweiterungsmethode ausführen, die von der Liste hängt. Das würde LoadAll() auf jeder Liste/Sammlung geben und es könnte von jedem IEnumerable lesen ... einige Leute könnten sagen, dass dies ein Missbrauch von Erweiterungsmethoden ist. Aber ich sage, es erlaubt Ihnen, so zu handeln, als ob Sie mehrfache Vererbung haben. –

+0

Gute Idee, obwohl meine LoadAll() Methode nicht wirklich generisch ist. Es wird abhängig vom zugrunde liegenden Objekttyp aus verschiedenen Tabellen geladen. Es mag einen Weg geben, es generisch zu machen, aber ich habe mich bisher nicht wirklich damit befasst. – jeremcc

0

6 von 1, halbes Dutzend anderer

So oder so ist es das Gleiche. Ich mache es nur, wenn ich Grund habe, benutzerdefinierten Code in BusinessObjectCollection hinzuzufügen.

Ohne es laden Methoden eine Liste zurückgeben erlaubt mir, mehr Code in einer allgemeinen Klasse zu schreiben und es funktioniert einfach. Wie eine Load-Methode.

9

Ich bevorzuge nur List<BusinessObject> zu verwenden. Typedefing fügt nur unnötigen Textbaustein zum Code hinzu. List<BusinessObject> ist ein bestimmter Typ, es ist nicht irgendein List Objekt, also ist es immer noch stark typisiert.

Noch wichtiger ist es, etwas zu deklarieren List<BusinessObject> macht es für jeden leichter den Code zu lesen, welche Arten sie zu tun haben, müssen sie nicht suchen, um herauszufinden, was ein BusinessObjectCollection ist und dann daran denken, dass es nur eine Liste ist . Mit typedefing müssen Sie eine konsistente (Wieder-) Benennungskonvention verlangen, die alle befolgen müssen, damit sie sinnvoll ist.

3

Sie sollten wahrscheinlich vermeiden, Ihre eigene Sammlung für diesen Zweck zu erstellen.Es ist ziemlich üblich, den Typ der Datenstruktur während Refactorings oder beim Hinzufügen neuer Features ein paar Mal zu ändern. Mit Ihrem Ansatz würden Sie mit einer separaten Klasse für BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree, etc. enden.

Ich sehe wirklich keinen Wert beim Erstellen dieser Klasse, nur weil der Klassenname besser lesbar ist. Ja, die Winkelsyntax ist etwas hässlich, aber sie ist Standard in C++, C# und Java, also, auch wenn Sie keinen Code schreiben, der sie verwendet, werden Sie die ganze Zeit darauf stoßen.

14

Es ist recommended, dass in der öffentlichen API nicht Liste verwenden <T>, aber Sammlung <T>

Wenn Sie von ihm erben, obwohl sind zu verwenden, sollten Sie sich gut, afaik.

1

Ich verwende generische Listen für fast alle Szenarien. Die einzige Zeit, die ich in Erwägung ziehen würde, eine abgeleitete Sammlung zu verwenden, ist, wenn ich sammlungsspezifische Elemente hinzufüge. Das Aufkommen von LINQ hat jedoch die Notwendigkeit dafür sogar verringert.

-1

dies ist die Art und Weise:

Return Arrays akzeptieren IEnumerable<T>

=)

+1

akzeptieren IEnumerable , gibt IEnumerable oder ReadOnlyCollection zurück, aber nie ein Array. Lesen Sie dies: http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-consided-somewhatful.aspx! –

+0

Schöne Sache über die Rückkehr IEnumerable ist, können Sie einfach Lazy Eval zu Ihrer gesamten App hinzufügen. –

0

Wie jemand anderes darauf hingewiesen, es öffentlich nicht zu belichten Liste empfohlen wird, und FxCop wird jammern, wenn Sie tun damit. Dazu gehören der Firma List erben wie in:

public MyTypeCollection : List<MyType> 

In den meisten Fällen öffentliche APIs IList (oder ICollection oder IEnumerable) gegebenenfalls aussetzen.

In Fällen, in denen Sie eine eigene benutzerdefinierte Sammlung wünschen, können Sie FxCop ruhig halten, indem Sie von Collection anstelle von List erben.

0

Wenn Sie Ihre eigene Sammlungsklasse erstellen, sollten Sie die Typen unter System.Collections.ObjectModel Namespace überprüfen.

Der Namespace definiert Basisklassen, die es den Implementierern erleichtern, benutzerdefinierte Sammlungen zu erstellen.

0

Ich neige dazu, es mit meiner eigenen Sammlung zu tun, wenn ich den Zugriff auf die tatsächliche Liste schützen möchte. Wenn Sie Geschäftsobjekte schreiben, besteht die Chance, dass Sie einen Haken benötigen, um zu wissen, ob Ihr Objekt hinzugefügt/entfernt wird. In diesem Sinne denke ich, dass BOCollection eine bessere Idee ist. Wenn das nicht erforderlich ist, ist List leichter. Sie sollten auch prüfen, ob Sie IList verwenden, um eine zusätzliche Abstraktionsschnittstelle bereitzustellen, wenn Sie eine Art von Proxys benötigen (z. B. löst eine gefälschte Sammlung Lazy Load aus der Datenbank)

Aber ... warum Castle ActiveRecord oder ein anderes ausgereiftes ORM-Framework nicht in Betracht ziehen ? :)

0

In den meisten Fällen gehe ich einfach mit dem List Weg, da es mir die ganze Funktionalität gibt, die ich in den 90% der Zeit brauche, und wenn etwas 'extra' benötigt wird, erben ich davon und das extra Bit codieren.

0

Ich würde dies tun:

using BusinessObjectCollection = List<BusinessObject>; 

Das schafft nur ein Alias ​​anstatt eine völlig neue Art. Ich bevorzuge die Verwendung der BusinessObject-Liste < direkt, weil es mir die Freiheit gibt, die zugrunde liegende Struktur der Sammlung irgendwann in der Zukunft zu ändern, ohne den Code zu ändern, der sie verwendet (solange ich dieselben Eigenschaften und Methoden bereitstelle).

0

try this out:

System.Collections.ObjectModel.Collection<BusinessObject> 

es unnötig macht, grundlegende Methode zu implementieren, wie Collection

tun
2

Sie beide verwenden können. Faulheit - ich meine Produktivität - Liste ist eine sehr nützliche Klasse, sie ist auch "umfassend" und offen gesagt voller YANGNI-Mitglieder.Gekoppelt mit dem vernünftigen Argumente/Empfehlung, auf denen die MSDN article bereits verknüpft über Liste als öffentliches Mitglied ausgesetzt wird, ziehe ich die „dritte“ Art und Weise:

persönlich verwende ich die Decorator-Muster nur zu, was ich von Liste brauche also:

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

noch weiter würde ich wahrscheinlich abstrakt OrderItemCollection in IOrderItemCollection so kann ich meine Implementierung von IOrderItemCollection über in der Zukunft in (ich ein anderes inneres enumerable Objekt wie das Erheben oder mehr likley für perf Verwendung kann es vorziehen, tauschen zu verwenden eine Schlüsselwertpaar-Sammlung oder einen Satz

4

Verwenden Sie den Typ List<BusinessObject>, wo Sie eine Liste von ihnen deklarieren müssen. Wenn Sie jedoch eine Liste mit BusinessObject zurücksenden, ziehen Sie in Betracht, IEnumerable<T>, IList<T> oder ReadOnlyCollection<T> zurückzugeben - also den schwächsten möglichen Vertrag zurückzugeben, der den Kunden zufriedenstellt.

Wenn Sie einer Liste "benutzerdefinierten Code" hinzufügen möchten, verwenden Sie die Codemethoden für den Listentyp. Fügen Sie diese Methoden wiederum dem schwächsten möglichen Vertrag, z.

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

Natürlich können Sie nicht und sollte nicht Staat mit Erweiterungsmethoden hinzufügen, wenn Sie also dahinter eine neue Eigenschaft und ein Feld hinzufügen müssen, verwenden Sie eine Unterklasse oder besser, eine Wrapper-Klasse speichern Dies.

Verwandte Themen