IEnumerable non garantisce che l'enumerazione due volte produrrà lo stesso risultato. In realtà, è abbastanza facile creare un esempio in cui myEnumerable.First()
restituisce valori diversi quando eseguito due volte:Esiste un modo canonico per "risolvere" un IEnumerable "dinamico"?
class A {
public A(string value) { Value = value; }
public string Value {get; set; }
}
static IEnumerable<A> getFixedIEnumerable() {
return new A[] { new A("Hello"), new A("World") };
}
static IEnumerable<A> getDynamicIEnumerable() {
yield return new A("Hello");
yield return new A("World");
}
static void Main(string[] args)
{
IEnumerable<A> fix = getFixedIEnumerable();
IEnumerable<A> dyn = getDynamicIEnumerable();
Console.WriteLine(fix.First() == fix.First()); // true
Console.WriteLine(dyn.First() == dyn.First()); // false
}
Questo non è solo un esempio accademico: Utilizzando il popolare from ... in ... select new A(...)
creerà esattamente questa situazione. Questo può portare a un comportamento imprevisto:
fix.First().Value = "NEW";
Console.WriteLine(fix.First().Value); // prints NEW
dyn.First().Value = "NEW";
Console.WriteLine(dyn.First().Value); // prints Hello
capisco perché questo accade. So anche che questo problema potrebbe essere risolto eseguendo ToList()
sull'enumerabile o ignorando ==
per la classe A
. Questa non è la mia domanda.
La domanda è: quando si scrive un metodo che accetta un IEnumerable arbitrario e si desidera la proprietà che la sequenza viene valutata solo una volta (e quindi i riferimenti sono "corretti"), qual è il modo canonico per fare ciò? ToList()
sembra essere usato principalmente, ma se la fonte è già stata riparata (ad esempio, se l'origine è una matrice), i riferimenti vengono copiati in una lista (inutilmente, poiché tutto ciò di cui ho bisogno è la proprietà fissa). C'è qualcosa di più adatto o è ToList()
la soluzione "canonica" per questo problema?
Per definizione un IEnumerable non dice che l'ordine non è garantito? Se l'ordine è richiesto per la tua implementazione stai utilizzando il tipo di dati sbagliato, no? Tutto quello che chiedi nel tuo contratto con IEnumerable è che gli elementi possono essere attraversati. IE: come dici tu, un elenco è più adatto. –