Pregunta

Sé mucho sobre C # pero este me está confundiendo y Google no está ayudando.

Tengo un rango de objetos IEnumerable. Quiero establecer una propiedad en el primero. Lo hago, pero cuando enumero el rango de objetos después de la modificación, no veo mi cambio.

Aquí hay un buen ejemplo del problema:

    public static void GenericCollectionModifier()
    {
        // 1, 2, 3, 4... 10
        var range = Enumerable.Range(1, 10);

        // Convert range into SubItem classes
        var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i});

        Write(items);  // Expect to output 1,2,3,4,5,6,7,8,9,10

        // Make a change
        items.First().MagicNumber = 42;

        Write(items);  // Expect to output 42,2,3,4,5,6,7,8,9,10
        // Actual output: 1,2,3,4,5,6,7,8,9,10
    }

    public static void Write(IEnumerable<SubItem> items)
    {
        Console.WriteLine(string.Join(", ", items.Select(item => item.MagicNumber.ToString()).ToArray()));
    }

    public class SubItem
    {
       public string Name;
       public int MagicNumber;
    }

¿Qué aspecto de C # detiene mi " MagicNumber = 42 " cambio de ser salida? ¿Hay alguna manera de hacer que mi cambio sea & Quot; stick & Quot; sin hacer alguna conversión funky a List < > o matriz?

¡Gracias! -Mike

¿Fue útil?

Solución

Cuando llamas a First () enumera el resultado de este bit de código:

Select(i => new SubItem() {Name = "foo", MagicNumber = i});

Tenga en cuenta que Select es un enumerador vago, lo que significa que solo hace la selección cuando le solicita un elemento (y lo hace cada cada vez que lo solicita). Los resultados no se almacenan en ningún lugar, por lo que cuando llama a elementos. Primero () obtiene una nueva instancia de SubItem. Cuando pasa elementos a Escribir, obtiene un montón de nuevas <=> instancias, no la que tenía antes.

Si desea almacenar el resultado de su selección y modificarlo, debe hacer algo como:

var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}).ToList();

Otros consejos

Sospecho que algo pasa en el fondo. Lo más probable es que los IEnumerables solo se puedan repetir una vez.

¿Funciona si agrega un 'ToList ()' después de la llamada a Select () al asignar a 'elementos'?

Lo único en lo que puedo pensar es en los elementos. Primero () pasa una copia de SubItem a tu en lugar de la referencia, así que cuando lo configuras el cambio no se lleva a cabo.

Tengo que asumir que tiene algo que ver con que IQueryable solo se pueda repetir una vez. Puede intentar cambiar esto:

// Convert range into SubItem classes
var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i});

a

// Convert range into SubItem classes
var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}).ToList();

Y vea si hay resultados diferentes.

No puede / no debe modificar una colección a través de un enumerador. Me sorprende que esto no arroje una excepción.

.First () es un método, no una propiedad. Devuelve una nueva instancia del objeto en la primera posición de su Enumerable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top