wake-up-neo.com

Ist es besser, Enumerable.Empty <T> () anstelle von new List <T> () zu verwenden, um IEnumerable <T> zu initialisieren?

Angenommen, Sie haben eine Klasse Person:

public class Person
{
   public string Name { get; set;}
   public IEnumerable<Role> Roles {get; set;}
}

Ich sollte natürlich die Rollen im Konstruktor instanziieren. Jetzt habe ich es mit einer Liste wie dieser gemacht:

public Person()
{
   Roles = new List<Role>();
}

Diese statische Methode habe ich jedoch im Namespace System.Linq Entdeckt

IEnumerable<T> Enumerable.Empty<T>();

Von MSDN :

Die Methode Empty(TResult)() speichert eine leere Sequenz vom Typ TResult. Wenn das Objekt, das es zurückgibt, aufgelistet wird, gibt es keine Elemente zurück.

In einigen Fällen ist diese Methode hilfreich, um eine leere Sequenz an eine benutzerdefinierte Methode zu übergeben, die eine IEnumerable(T) übernimmt. Es kann auch verwendet werden, um ein neutrales Element für Methoden wie Union zu generieren. Ein Beispiel für diese Verwendung von finden Sie im Abschnitt Beispiel

Also ist es besser, den Konstruktor so zu schreiben? Benutzt du es? Warum? oder wenn nicht, warum nicht?

public Person()
{
   Roles = Enumerable.Empty<Role>();
}
125
Stéphane

Ich denke, die meisten Beiträge haben den Hauptpunkt verfehlt. Auch wenn Sie ein leeres Array oder eine leere Liste verwenden, handelt es sich um Objekte, die im Speicher abgelegt sind. Als Müllsammler muss er sich um sie kümmern. Wenn Sie mit Anwendungen mit hohem Durchsatz arbeiten, kann dies spürbare Auswirkungen haben.

Enumerable.Empty erstellt kein Objekt pro Aufruf, wodurch der GC weniger belastet wird.

Befindet sich der Code an einem Ort mit geringem Durchsatz, müssen jedoch ästhetische Aspekte berücksichtigt werden.

142
Vadim Chekan

Meiner Ansicht nach Enumerable.Empty<T> ist besser, weil es expliziter ist: Ihr Code zeigt deutlich Ihre Absichten. Es könnte auch ein bisschen effizienter sein, aber das ist nur ein sekundärer Vorteil.

84
Tommy Carlier

Mal sehen, wie Enumerable.Empty<T> ist implementiert.

Es gibt EmptyEnumerable<T>.Instance, definiert als:

internal class EmptyEnumerable<T>
{
    public static readonly T[] Instance = new T[0];
}

Statische Felder für generische Typen werden pro generischem Typparameter zugewiesen. Dies bedeutet, dass die Laufzeit diese leeren Arrays nur für die vom Benutzercode benötigten Typen träge erstellen und die Instanzen so oft wie nötig wiederverwenden kann, ohne den Garbage Collector zu belasten.

Nämlich:

Debug.Assert(ReferenceEquals(Enumerable.Empty<int>(), Enumerable.Empty<int>()));
21
Drew Noakes

Angenommen, Sie möchten die Roles -Eigenschaft tatsächlich auf irgendeine Weise auffüllen und kapseln sie dann ein, indem Sie den Setter privat machen und ihn in einer neuen Liste im Konstruktor initialisieren:

public class Person
{
    public string Name { get; set; }
    public IList<Role> Roles { get; private set; }

    public Person()
    {
        Roles = new List<Role>();
    }
}

Wenn Sie wirklich wirklich den öffentlichen Setter haben möchten, lassen Sie Roles mit einem Wert von null und vermeiden Sie die Objektzuordnung.

12
Neil Barnwell

Das Problem bei Ihrem Ansatz ist, dass Sie der Sammlung keine Elemente hinzufügen können. Ich hätte eine private Struktur wie list und würde die Elemente dann als Enumerable verfügbar machen:

public class Person
{
    private IList<Role> _roles;

    public Person()
    {
        this._roles = new List<Role>();
    }

    public string Name { get; set; }

    public void AddRole(Role role)
    {
        //implementation
    }

    public IEnumerable<Role> Roles
    {
        get { return this._roles.AsEnumerable(); }
    }
}

Wenn Sie vorhaben, dass eine andere Klasse die Liste der Rollen erstellt (was ich nicht empfehlen würde), würde ich die Aufzählung überhaupt nicht persönlich initialisieren.

7
Lee

Das typische Problem beim Anzeigen der privaten Liste als IEnumerable besteht darin, dass der Client Ihrer Klasse sich durch Casting damit anlegen kann. Dieser Code würde funktionieren:

  var p = new Person();
  List<Role> roles = p.Roles as List<Role>;
  roles.Add(Role.Admin);

Sie können dies vermeiden, indem Sie einen Iterator implementieren:

public IEnumerable<Role> Roles {
  get {
    foreach (var role in mRoles)
      yield return role;
  }
}
6
Hans Passant

Das größere Problem hier wäre, Roles als öffentliches Feld verfügbar zu machen.

folgendes sieht besser aus:

public class Person
{
   public string Name { get; set; }  

   private List<Role> _roles = null;
   public IEnumerable<Role> Roles 
   {
      get { 
        if (_roles != null) 
          return _roles;
        else
          return Enumerable.Empty<Role>();
        }
   }
}

Und vielleicht sollten Sie es als ReadonlyCollection zurückgeben, je nachdem, wie Sie es verwenden möchten.

Und Enumerable.Empty ist hier nicht better, nur ein bisschen effizienter, wenn Rollen normalerweise leer bleiben.

5
Henk Holterman