Pregunta

Tengo una lista de estructuras y quiero cambiar un elemento.Por ejemplo :

MyList.Add(new MyStruct("john");
MyList.Add(new MyStruct("peter");

Ahora quiero cambiar un elemento:

MyList[1].Name = "bob"

Sin embargo, cada vez que intento hacer esto aparece el siguiente error:

No se puede modificar el valor de retorno de system.collections.generic.list.Tis [int] 'porque no es una variable

Si uso una lista de clases, el problema no ocurre.

Supongo que la respuesta tiene que ver con que las estructuras sean un tipo de valor.

Entonces, si tengo una lista de estructuras, ¿debería tratarlas como solo lectura?Si necesito cambiar elementos en una lista, ¿debería usar clases y no estructuras?

¿Fue útil?

Solución

MyList[1] = new MyStruct("bob");

Las estructuras en C# casi siempre deben diseñarse para ser inmutables (es decir, no tener forma de cambiar su estado interno una vez creadas).

En su caso, lo que quiere hacer es reemplazar toda la estructura en el índice de matriz especificado, no intentar cambiar solo una propiedad o campo.

Otros consejos

No exactamente.El diseño de un tipo como clase o estructura no debería depender de su necesidad de almacenarlo en colecciones :) Debería observar la 'semántica' necesaria

El problema que estás viendo se debe a la semántica del tipo de valor.Cada variable/referencia de tipo de valor es una nueva instancia.Cuando tu dices

Struct obItem = MyList[1];

lo que sucede es que se crea una nueva instancia de la estructura y todos los miembros se copian uno por uno.Para que tengas un clon de MyList[1], es decir2 instancias.Ahora, si modifica obItem, no afecta al original.

obItem.Name = "Gishu";  // MyList[1].Name still remains "peter"

Ahora tengan paciencia conmigo durante 2 minutos (esto lleva un tiempo tragarlo...Lo hizo por mí :) Si realmente necesita estructuras para almacenar en una colección y modificarse como lo indicó en su pregunta, tendrá que hacer que su estructura exponga una interfaz (Sin embargo esto resultará en el boxeo.).Luego puede modificar la estructura real a través de una referencia de interfaz, que hace referencia al objeto encuadrado.

El siguiente fragmento de código ilustra lo que acabo de decir arriba

public interface IMyStructModifier
{
    String Name { set; }
}
public struct MyStruct : IMyStructModifier ...

List<Object> obList = new List<object>();
obList.Add(new MyStruct("ABC"));
obList.Add(new MyStruct("DEF"));

MyStruct temp = (MyStruct)obList[1];
temp.Name = "Gishu";
foreach (MyStruct s in obList) // => "ABC", "DEF"
{
    Console.WriteLine(s.Name);
}

IMyStructModifier temp2 = obList[1] as IMyStructModifier;
temp2.Name = "Now Gishu";
foreach (MyStruct s in obList) // => "ABC", "Now Gishu"
{
    Console.WriteLine(s.Name);
}

HTH.Buena pregunta.
Actualizar: @Hath: me hiciste correr para comprobar si pasé por alto algo tan simple.(Sería inconsistente si las propiedades del definidor y los métodos no lo hicieran; el universo .Net todavía está equilibrado :)
El método de establecimiento no funciona
obList2[1] devuelve una copia cuyo estado sería modificado.La estructura original de la lista permanece sin modificaciones.Entonces Set-via-Interface parece ser la única forma de hacerlo.

List<MyStruct> obList2 = new List<MyStruct>();
obList2.Add(new MyStruct("ABC"));
obList2.Add(new MyStruct("DEF"));
obList2[1].SetName("WTH");
foreach (MyStruct s in obList2) // => "ABC", "DEF"
{
    Console.WriteLine(s.Name);
}

No se trata tanto de que las estructuras sean "inmutables".

El verdadero problema subyacente es que las estructuras son de tipo Valor, no de tipo Referencia.Entonces, cuando saca una "referencia" a la estructura de la lista, se crea una nueva copia de la estructura completa.Por lo tanto, cualquier cambio que realice en él cambiará la copia, no la versión original en la lista.

Como dice Andrew, hay que reemplazar toda la estructura.En ese punto, creo que debes preguntarte por qué estás usando una estructura en primer lugar (en lugar de una clase).Asegúrese de no hacerlo por preocupaciones de optimización prematura.

No hay nada de malo en las estructuras que tienen campos expuestos o que permiten la mutación mediante establecedores de propiedades.Sin embargo, las estructuras que se mutan en respuesta a métodos o captadores de propiedades son peligrosas porque el sistema permitirá que se llamen métodos o captadores de propiedades en instancias de estructuras temporales;Si los métodos o captadores realizan cambios en la estructura, esos cambios terminarán siendo descartados.

Desafortunadamente, como habrás notado, las colecciones integradas en .net son realmente débiles a la hora de exponer los objetos de tipo valor contenidos en ellas.Su mejor opción suele ser hacer algo como:

  MyStruct temp = myList[1];
  temp.Name = "Albert";
  myList[1] = temp;

Algo molesto y nada seguro para subprocesos.Sigue siendo una mejora con respecto a una Lista de un tipo de clase, donde hacer lo mismo podría requerir:

  myList[1].Name = "Albert";

pero también podría requerir:

  myList[1] = myList[1].Withname("Albert");

o tal vez

  myClass temp = (myClass)myList[1].Clone();
  temp.Name = "Albert";
  myList[1] = temp;

o tal vez alguna otra variación.Uno realmente no podría saberlo a menos que examinara myClass y el otro código que coloca las cosas en la lista.Es muy posible que uno no pueda saber si el primer formulario es seguro sin examinar el código en ensamblados a los que no se tiene acceso.Por el contrario, si Nombre es un campo expuesto de MyStruct, el método que proporcioné para actualizarlo funcionará, independientemente de qué más contenga MyStruct, o de lo que otras cosas hayan hecho con myList antes de que se ejecute el código o de lo que puedan esperar. hazlo después.

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