In meinem Code muss ein IEnumerable<>
mehrmals verwendet werden, daher wird der Resharper-Fehler "Mögliche Mehrfachaufzählung von IEnumerable
" angezeigt .
Beispielcode:
public List<object> Foo(IEnumerable<object> objects)
{
if (objects == null || !objects.Any())
throw new ArgumentException();
var firstObject = objects.First();
var list = DoSomeThing(firstObject);
var secondList = DoSomeThingElse(objects);
list.AddRange(secondList);
return list;
}
- Ich kann den
objects
Parameter so ändernList
und dann die mögliche Mehrfachaufzählung vermeiden, aber dann erhalte ich nicht das höchste Objekt, das ich verarbeiten kann. - Eine andere Sache, die ich tun kann, ist, das
IEnumerable
zuList
Beginn der Methode in zu konvertieren :
public List<object> Foo(IEnumerable<object> objects)
{
var objectList = objects.ToList();
// ...
}
Das ist aber nur umständlich .
Was würden Sie in diesem Szenario tun?
quelle
IReadOnlyCollection(T)
(neu mit .net 4.5) als beste Schnittstelle, um die Idee zu vermitteln, dass es sich um eineIEnumerable(T)
handelt, die mehrfach aufgezählt werden soll. Wie diese Antwort besagt, ist sieIEnumerable(T)
selbst so allgemein gehalten, dass sie sich möglicherweise sogar auf nicht zurücksetzbare Inhalte bezieht, die ohne Nebenwirkungen nicht erneut aufgezählt werden können. AberIReadOnlyCollection(T)
impliziert Wiederholbarkeit..ToList()
zu Beginn der Methode tun , müssen Sie zuerst prüfen, ob der Parameter nicht null ist. Das bedeutet, dass Sie zwei Stellen erhalten, an denen Sie eine ArgumentException auslösen: Wenn der Parameter null ist und keine Elemente enthält.IReadOnlyCollection<T>
vs gelesenIEnumerable<T>
und dann eine Frage zur VerwendungIReadOnlyCollection<T>
als Parameter und in welchen Fällen gestellt. Ich denke, die Schlussfolgerung, zu der ich schließlich gekommen bin, ist die Logik, der ich folgen muss. Dass es dort verwendet werden sollte, wo eine Aufzählung erwartet wird, nicht unbedingt dort, wo es mehrere Aufzählungen geben könnte.Wenn Ihre Daten immer wiederholbar sind, machen Sie sich vielleicht keine Sorgen. Sie können es jedoch auch abrollen. Dies ist besonders nützlich, wenn die eingehenden Daten sehr groß sein können (z. B. Lesen von der Festplatte / dem Netzwerk):
Hinweis: Ich habe die Semantik von DoSomethingElse ein wenig geändert, dies dient jedoch hauptsächlich dazu, die nicht gerollte Verwendung anzuzeigen. Sie können den Iterator beispielsweise erneut umbrechen. Sie könnten es auch zu einem Iteratorblock machen, was nett sein könnte; dann gibt es keine
list
- und Sie würdenyield return
die Artikel so erhalten, wie Sie sie erhalten, anstatt sie einer Liste hinzuzufügen, die zurückgegeben werden soll.quelle
Die Verwendung von
IReadOnlyCollection<T>
oderIReadOnlyList<T>
in der Methodensignatur anstelle vonIEnumerable<T>
hat den Vorteil, dass explizit angegeben wird, dass Sie möglicherweise die Anzahl vor dem Iterieren überprüfen oder aus einem anderen Grund mehrmals iterieren müssen.Sie haben jedoch einen großen Nachteil, der zu Problemen führen kann, wenn Sie versuchen, Ihren Code so umzugestalten, dass er Schnittstellen verwendet, um ihn beispielsweise testbarer und für dynamisches Proxying benutzerfreundlicher zu machen. Der entscheidende Punkt ist, dass
IList<T>
nicht vonIReadOnlyList<T>
und für andere Sammlungen und ihre jeweiligen schreibgeschützten Schnittstellen geerbt wird. (Kurz gesagt, dies liegt daran, dass .NET 4.5 die ABI-Kompatibilität mit früheren Versionen beibehalten wollte. Sie nutzten jedoch nicht einmal die Gelegenheit, dies in .NET Core zu ändern. )Dies bedeutet, dass Sie dies nicht können, wenn Sie eine
IList<T>
von einem Teil des Programms erhalten und an einen anderen Teil übergeben möchten, der eine erwartetIReadOnlyList<T>
! Sie können jedoch eineIList<T>
als übergebenIEnumerable<T>
.Letztendlich
IEnumerable<T>
ist dies die einzige schreibgeschützte Schnittstelle, die von allen .NET-Sammlungen einschließlich aller Sammlungsschnittstellen unterstützt wird. Jede andere Alternative wird Sie beißen, wenn Sie feststellen, dass Sie sich von einigen Architekturentscheidungen ausgeschlossen haben. Ich denke, es ist der richtige Typ für Funktionssignaturen, um auszudrücken, dass Sie nur eine schreibgeschützte Sammlung wünschen.(Beachten Sie, dass Sie immer eine
IReadOnlyList<T> ToReadOnly<T>(this IList<T> list)
Erweiterungsmethode schreiben können, die einfach umgewandelt wird, wenn der zugrunde liegende Typ beide Schnittstellen unterstützt. Sie müssen sie jedoch beim Refactoring überall manuell hinzufügen, wo diesIEnumerable<T>
immer kompatibel ist.)Wie immer ist dies kein absoluter Kompromiss. Wenn Sie datenbankintensiven Code schreiben, bei dem eine versehentliche Mehrfachaufzählung eine Katastrophe darstellen würde, bevorzugen Sie möglicherweise einen anderen Kompromiss.
quelle
Wenn das Ziel wirklich darin besteht, mehrere Aufzählungen zu verhindern, ist die Antwort von Marc Gravell die zu lesende, aber wenn Sie dieselbe Semantik beibehalten, können Sie einfach die Redundanz
Any
und dieFirst
Aufrufe entfernen und fortfahren mit:Beachten Sie, dass dies voraussetzt, dass Sie
IEnumerable
nicht generisch sind oder zumindest ein Referenztyp sein müssen.quelle
objects
wird immer noch an DoSomethingElse übergeben, das eine Liste zurückgibt, sodass die Möglichkeit besteht, dass Sie immer noch zweimal aufzählen. In beiden Fällen haben Sie die Datenbank zweimal aufgerufen, wenn es sich bei der Sammlung um eine LINQ to SQL-Abfrage handelte.First
eine Ausnahme für eine leere Liste ausgelöst wird. Ich denke nicht, dass es möglich ist zu sagen, niemals eine Ausnahme auf eine leere Liste zu werfen oder immer eine Ausnahme auf eine leere Liste zu werfen. Es kommt darauf an ...Normalerweise überlade ich meine Methode in dieser Situation mit IEnumerable und IList.
Ich erkläre in den zusammenfassenden Kommentaren der Methoden, dass der Aufruf von IEnumerable eine .ToList () ausführt.
Der Programmierer kann .ToList () auf einer höheren Ebene auswählen, wenn mehrere Vorgänge verkettet werden, und dann die IList-Überladung aufrufen oder meine IEnumerable-Überladung dafür sorgen lassen.
quelle
Wenn Sie nur das erste Element überprüfen müssen, können Sie einen Blick darauf werfen, ohne die gesamte Sammlung zu wiederholen:
quelle
Zunächst einmal bedeutet diese Warnung nicht immer so viel. Normalerweise habe ich es deaktiviert, nachdem ich sichergestellt hatte, dass es sich nicht um einen Performance-Flaschenhals handelt. Es bedeutet nur, dass das
IEnumerable
zweimal ausgewertet wird, was normalerweise kein Problem ist, es sei denn, dasevaluation
selbst dauert lange. Auch wenn es lange dauert, verwenden Sie in diesem Fall beim ersten Mal nur ein Element.In diesem Szenario können Sie die leistungsstarken Linq-Erweiterungsmethoden auch noch stärker nutzen.
Es ist
IEnumerable
in diesem Fall möglich, das nur einmal mit etwas Aufwand zu bewerten , aber zuerst das Profil zu erstellen und zu prüfen, ob es wirklich ein Problem ist.quelle
IEnumerables
dass jedes Mal, wenn Sie es wiederholen, unterschiedliche Ergebnisse erzielt werden oder dass die Iteration sehr lange dauert. Siehe Marc Gravells Antwort - Er sagt auch in erster Linie "vielleicht keine Sorge". Die Sache ist - In vielen Fällen, in denen Sie dies sehen, müssen Sie sich keine Sorgen machen.