Ich habe gerade einen interessanten Artikel mit dem Titel Getting too cute with c # yield return gelesen
Ich habe mich gefragt, wie ich am besten feststellen kann, ob es sich bei IEnumerable um eine tatsächliche Auflistung von Enumerables handelt oder ob es sich um einen mit dem Schlüsselwort yield generierten Zustandsautomaten handelt.
Beispielsweise könnten Sie DoubleXValue (aus dem Artikel) in etwas ändern, wie:
private void DoubleXValue(IEnumerable<Point> points)
{
if(points is List<Point>)
foreach (var point in points)
point.X *= 2;
else throw YouCantDoThatException();
}
Frage 1) Gibt es einen besseren Weg, dies zu tun?
Frage 2) Sollte ich mir darüber Gedanken machen, wenn ich eine API erstelle?
c#
api-design
ConditionRacer
quelle
quelle
ICollection<T>
da dies nicht für alle Sammlungen der Fall istList<T>
. BeispielsweisePoint[]
implementieren Arrays diesIList<T>
jedoch nichtList<T>
.IEnumerable
ist in dem Sinne unveränderlich, dass Sie eine Sammlung nicht ändern (hinzufügen / entfernen) können, während Sie sie auflisten. Wenn die Objekte in der Liste jedoch veränderlich sind, ist es durchaus sinnvoll, diese zu ändern, während Sie die Liste auflisten.ToList
? msdn.microsoft.com/en-us/library/bb342261.aspx Es erkennt nicht, ob es durch Yield generiert wurde, sondern macht es irrelevant.Antworten:
Wie ich es verstehe, scheint Ihre Frage auf einer falschen Prämisse zu beruhen. Lassen Sie mich sehen, ob ich die Argumentation rekonstruieren kann:
Das Problem ist, dass die zweite Prämisse falsch ist. Selbst wenn Sie feststellen könnten, ob eine bestimmte IEnumerable das Ergebnis einer Iteratorblocktransformation ist (und ja, es gibt Möglichkeiten, dies zu tun), würde dies nicht helfen, da die Annahme falsch ist. Lassen Sie uns veranschaulichen, warum.
Okay, wir haben vier Methoden. S1 und S2 sind automatisch generierte Sequenzen; S3 und S4 sind manuell erzeugte Sequenzen. Nehmen wir nun an, wir haben:
Das Ergebnis für S1 und S4 ist 0; Jedes Mal, wenn Sie die Sequenz aufzählen, erhalten Sie einen neuen Verweis auf ein erstelltes M. Das Ergebnis für S2 und S3 ist 100; Jedes Mal, wenn Sie die Sequenz aufzählen, erhalten Sie denselben Verweis auf M, den Sie beim letzten Mal erhalten haben. Ob der Sequenzcode automatisch generiert wird oder nicht, ist orthogonal zur Frage, ob die aufgezählten Objekte eine referenzielle Identität haben oder nicht. Diese beiden Eigenschaften - automatische Generierung und referenzielle Identität - haben eigentlich nichts miteinander zu tun. Der Artikel, den Sie verlinkt haben, widerspricht ihnen etwas.
Sofern ein Sequenzanbieter nicht dokumentiert ist, dass er Objekte mit referentieller Identität immer anbietet , ist es nicht ratsam , dies anzunehmen.
quelle
Ich denke, das Schlüsselkonzept ist, dass Sie jede
IEnumerable<T>
Sammlung als unveränderlich behandeln sollten : Sie sollten die Objekte daraus nicht ändern, Sie sollten eine neue Sammlung mit neuen Objekten erstellen:(Oder schreiben Sie dasselbe mit LINQ genauer
Select()
.)Wenn Sie die Elemente in der Auflistung tatsächlich ändern möchten, verwenden Sie nicht
IEnumerable<T>
, verwenden SieIList<T>
(oder möglicherweise,IReadOnlyList<T>
wenn Sie die Auflistung selbst nicht ändern möchten, nur die Elemente in der Auflistung, und Sie sind auf .Net 4.5):Auf diese Weise
IEnumerable<T>
schlägt die Kompilierung fehl , wenn jemand versucht, Ihre Methode mit zu verwenden .quelle
IEnumerable
mehr als einmal zu wiederholen. Die Notwendigkeit, dies mehr als einmal zu tun, kann vermieden werden, indemToList()
die Liste aufgerufen und durchlaufen wird , obwohl ich in dem speziellen Fall, der durch das OP gezeigt wird, Svicks Lösung bevorzuge, dass DoubleXValue auch eine IEnumerable zurückgibt. Natürlich würde ich in echtem Code wahrscheinlich verwendenLINQ
, um diese Art von Code zu generierenIEnumerable
. Die Wahl von svickyield
ist jedoch im Zusammenhang mit der Frage des OP sinnvoll.Select()
. Und in Bezug auf mehrere Iterationen vonIEnumerable
: ReSharper ist dabei hilfreich, da es Sie warnen kann, wenn Sie dies tun.Ich persönlich denke, das in diesem Artikel hervorgehobene Problem rührt von der übermäßigen Nutzung der
IEnumerable
Benutzeroberfläche durch viele C # -Entwickler in diesen Tagen her. Es scheint der Standardtyp geworden zu sein, wenn Sie eine Sammlung von Objekten benötigen - aber es gibt eine Menge Informationen,IEnumerable
die Ihnen einfach nicht sagen ... Entscheidend ist, ob sie erneut bestätigt wurden oder nicht *.Wenn Sie feststellen, dass Sie feststellen müssen , ob a
IEnumerable
wirklich einIEnumerable
oder etwas anderes ist, ist die Abstraktion durchgesickert und Sie befinden sich wahrscheinlich in einer Situation, in der Ihr Parametertyp etwas zu locker ist. Wenn Sie die zusätzlichen Informationen benötigen, dieIEnumerable
allein nicht zur Verfügung stehen, machen Sie diese Anforderung explizit, indem Sie eine der anderen Schnittstellen wieICollection
oder auswählenIList
.Edit für die Downvoter Bitte gehen Sie zurück und lesen Sie die Frage sorgfältig. Das OP fragt nach einer Möglichkeit, um sicherzustellen, dass
IEnumerable
Instanzen materialisiert wurden, bevor sie an seine API-Methode übergeben werden. Meine Antwort beantwortet diese Frage. Es gibt ein größeres Problem in Bezug auf die ordnungsgemäße VerwendungIEnumerable
, und die Erwartungen an den vom OP eingefügten Code beruhen sicherlich auf einem Missverständnis dieses umfassenderen Problems, aber das OP fragte nicht, wie es richtig verwendetIEnumerable
oder wie mit unveränderlichen Typen gearbeitet werden soll . Es ist nicht fair, mich dafür zu beleidigen, dass ich eine nicht gestellte Frage nicht beantwortet habe.* Ich verwende den Begriff
reify
, andere verwendenstabilize
odermaterialize
. Ich glaube nicht, dass die Community gerade eine gemeinsame Konvention verabschiedet hat.quelle
ICollection
undIList
ist, dass sie veränderlich sind (oder zumindest so aussehen).IReadOnlyCollection
undIReadOnlyList
von .Net 4.5 lösen einige dieser Probleme.