it-swarm.com.de

Ist es eine gute Praxis, eine Klassensammlung einer anderen Klasse zu erstellen?

Nehmen wir an, ich habe eine CarKlasse:

public class Car
{
    public string Engine { get; set; }
    public string Seat { get; set; }
    public string Tires { get; set; }
}

Nehmen wir an, wir erstellen ein System für einen Parkplatz. Ich werde einen Großteil der Klasse Car verwenden, also erstellen wir eine Klasse CarCollection, die möglicherweise einige zusätzliche Methoden enthält wie FindCarByModel:

public class CarCollection
{
    public List<Car> Cars { get; set; }

    public Car FindCarByModel(string model)
    {
        // code here
        return new Car();
    }
}

Was ist die beste Vorgehensweise, wenn ich eine Klasse ParkingLot mache?

Option 1 :

public class ParkingLot
{
    public List<Car> Cars { get; set; }
    //some other properties
}

Option 2 :

public class ParkingLot
{
    public CarCollection Cars { get; set; }
    //some other properties
}

Ist es überhaupt eine gute Praxis, ein ClassCollection eines anderen Class zu erstellen?

35
Luis

Vor Generika in .NET war es üblich, 'typisierte' Sammlungen zu erstellen, sodass Sie für jeden Typ, den Sie gruppieren mussten, class CarCollection Usw. haben. In .NET 2.0 wurde mit der Einführung von Generics eine neue Klasse List<T> Eingeführt, die es Ihnen erspart, CarCollection usw. zu erstellen, da Sie List<Car> Erstellen können.

Meistens werden Sie feststellen, dass List<T> Für Ihre Zwecke ausreichend ist. Es kann jedoch vorkommen, dass Sie ein bestimmtes Verhalten in Ihrer Sammlung haben möchten. Wenn Sie glauben, dass dies der Fall ist, haben Sie ein Paar von Optionen:

  • Erstellen Sie eine Klasse, die List<T> Einschließt, zum Beispiel public class CarCollection { private List<Car> cars = new List<Car>(); public void Add(Car car) { this.cars.Add(car); }}
  • Erstellen Sie eine benutzerdefinierte Sammlung public class CarCollection : CollectionBase<Car> {}

Wenn Sie sich für den Kapselungsansatz entscheiden, sollten Sie den Enumerator mindestens verfügbar machen, damit Sie ihn wie folgt deklarieren:

public class CarCollection : IEnumerable<Car>
{
    private List<Car> cars = new List<Car>();

    public IEnumerator<Car> GetEnumerator() { return this.cars.GetEnumerator(); }
}

Ohne dies können Sie kein foreach über die Sammlung ausführen.

Einige Gründe, warum Sie möglicherweise eine benutzerdefinierte Sammlung erstellen möchten, sind:

  • Sie möchten nicht alle Methoden in IList<T> Oder ICollection<T> Vollständig verfügbar machen.
  • Sie möchten zusätzliche Aktionen ausführen, wenn Sie ein Element zur Sammlung hinzufügen oder daraus entfernen

Ist es eine gute Praxis? Nun, das hängt davon ab, warum Sie es tun. Wenn es zum Beispiel einer der Gründe ist, die ich oben aufgeführt habe, dann ja.

Microsoft macht das ziemlich regelmäßig, hier sind einige relativ neue Beispiele:

Was Ihre FindBy -Methoden betrifft, wäre ich versucht, sie in Erweiterungsmethoden zu setzen, damit sie für jede Sammlung verwendet werden können, die Autos enthält:

public static class CarLookupQueries
{
    public static Car FindByLicencePlate(this IEnumerable<Car> source, string licencePlate)
    {
        return source.SingleOrDefault(c => c.LicencePlate == licencePlate);
    }

    ...
}

Dies trennt das Anliegen, die Sammlung abzufragen, von der Klasse, in der die Autos gelagert werden.

40
Trevor Pilley

Nein. Die Erstellung von XXXCollection -Klassen geriet mit dem Aufkommen von Generika in .NET 2.0 ziemlich aus der Mode. Tatsächlich gibt es die raffinierte LINQ-Erweiterung Cast<T>(), mit der die Leute heutzutage Dinge aus diesen benutzerdefinierten Formaten herausholen.

9
Jesse C. Slicer

Es ist oft praktisch, domänenorientierte Methoden zum Suchen/Slice-Auflistungen zu haben, wie im obigen FindByCarModel-Beispiel, aber es ist nicht erforderlich, Wrapper-Auflistungsklassen zu erstellen. In dieser Situation werde ich jetzt normalerweise eine Reihe von Erweiterungsmethoden erstellen.

public static class CarExtensions
{
    public static IEnumerable<Car> ByModel(this IEnumerable<Car> cars, string model)
    {
        return cars.Where(car => car.Model == model);
    }
}

Sie fügen dieser Klasse so viele Filter- oder Dienstprogrammmethoden hinzu, wie Sie möchten, und Sie können sie überall dort verwenden, wo Sie IEnumerable<Car> Haben, einschließlich aller ICollection<Car>, Arrays von Car, IList<Car> Usw.

Da unsere Persistenzlösung einen LINQ-Anbieter hat, werde ich häufig auch ähnliche Filtermethoden erstellen, die IQueryable<T> Verarbeiten und zurückgeben, damit wir diese Operationen auch auf das Repository anwenden können.

Die Redewendung von .NET (naja, C #) hat sich seit 1.1 stark verändert. Das Verwalten von benutzerdefinierten Sammlungsklassen ist ein Problem, und Sie profitieren nur wenig vom Erben von CollectionBase<T>, Das Sie mit der Erweiterungsmethodenlösung nicht erhalten, wenn Sie nur domänenspezifische Filter- und Auswahlmethoden benötigen.

2
Neil Hewitt

Ich denke, dass der einzige Grund, eine spezielle Klasse für das Halten einer Sammlung anderer Elemente zu erstellen, darin bestehen sollte, etwas Wertvolles hinzuzufügen, etwas mehr als nur eine Instanz von IList oder einen anderen Typ von zu kapseln/zu erben Sammlung.

Zum Beispiel in Ihrem Fall das Hinzufügen einer Funktion, die Unterlisten von Autos zurückgibt, die auf geraden/unebenen Stellplätzen geparkt sind ... Und selbst dann ... vielleicht nur, wenn es oft wiederverwendet wird, weil es nur eine Zeile mit einem Nice LinQ benötigt Funktion und wird nur einmal verwendet, was ist der Sinn? KUSS !

Wenn Sie vorhaben, viele Sortier-/Suchmethoden anzubieten, dann denke ich, dass dies nützlich sein könnte, da sie hier in diese spezielle Sammlungsklasse gehören sollten. Dies ist auch eine gute Möglichkeit, die Komplexität einiger "Such" -Abfragen oder was auch immer Sie in einer Sortier-/Suchmethode tun könnten, zu "verbergen".

1
Jalayn