IEnumerable no garantiza que enumerar dos veces arroje el mismo resultado. De hecho, es bastante fácil de crear un ejemplo en el myEnumerable.First()
devuelve valores diferentes cuando se ejecuta dos veces:¿Existe alguna manera canónica de "arreglar" un IEnumerable "dinámico"?
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
}
Esto no es sólo un ejemplo académico: El uso de la popular from ... in ... select new A(...)
creará exactamente esta situación. Esto puede conducir a un comportamiento inesperado:
fix.First().Value = "NEW";
Console.WriteLine(fix.First().Value); // prints NEW
dyn.First().Value = "NEW";
Console.WriteLine(dyn.First().Value); // prints Hello
entiendo por qué sucede esto. también sé que esto podría ser fijado mediante la ejecución de ToList()
en el Enumerable o por razones imperiosas ==
para la clase A
. Esa no es mi pregunta.
La pregunta es: Cuando escribe un método que toma un IEnumerable arbitrario y desea la propiedad de que la secuencia solo se evalúa una vez (y luego las referencias son "correctas"), ¿cuál es la manera canónica de hacerlo? ToList()
parece que se usa principalmente, pero si la fuente ya está fijada (por ejemplo, si la fuente es una matriz), las referencias se copian a una lista (innecesariamente, ya que todo lo que necesito es la propiedad fija). ¿Hay algo más adecuado o es ToList()
la solución "canónica" para este problema?
Por definición, ¿un IEnumerable no dice que el orden no está garantizado? Si se requiere orden para su implementación, está utilizando el tipo de datos incorrecto, ¿no? Todo lo que pides en tu contrato con IEnumerable es que los elementos se pueden recorrer IE: Como dices, una lista es más adecuada. –