Changer la valeur d’un élément dans une liste de structures

J’ai une liste de structures et je veux changer un élément. Par exemple :

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

Maintenant, je veux changer un élément:

 MyList[1].Name = "bob" 

Cependant, chaque fois que j’essaie de le faire, j’obtiens l’erreur suivante:

Impossible de modifier la valeur de retour de System.Collections.Generic.List.this [int] ‘car il ne s’agit pas d’une variable

Si j’utilise une liste de classes, le problème ne se produit pas.

Je suppose que la réponse est que les structures sont un type de valeur.

Donc, si j’ai une liste de structures, dois-je les traiter en lecture seule ? Si je dois changer des éléments dans une liste, je devrais utiliser des classes et non des structures?

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

    Les structures en C # devraient presque toujours être conçues pour être immuables (c’est-à-dire qu’elles n’ont aucun moyen de changer leur état interne une fois qu’elles ont été créées).

    Dans votre cas, vous voulez remplacer l’intégralité de la structure dans l’index de tableau spécifié, sans essayer de modifier une seule propriété ou un seul champ.

    Pas assez. Concevoir un type en tant que classe ou struct ne doit pas être dicté par votre besoin de le stocker dans des collections 🙂 Vous devriez regarder la “sémantique” nécessaire

    Le problème que vous rencontrez est dû à la sémantique du type de valeur. Chaque variable / référence de type valeur est une nouvelle instance. Quand tu dis

     Struct obItem = MyList[1]; 

    ce qui se passe, c’est qu’une nouvelle instance de la structure est créée et que tous les membres sont copiés un par un. Donc, vous avez un clone de MyList [1], soit 2 instances. Maintenant, si vous modifiez l’object, cela n’affecte pas l’original.

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

    Maintenant, restz avec moi pendant 2 minutes ici (Cela prend du temps à avaler… il a fait pour moi 🙂 Si vous avez vraiment besoin de stocker des structures dans une collection et de les modifier comme vous l’avez indiqué dans votre question, vous devrez votre struct expose une interface ( cependant cela entraînera la boxe ). Vous pouvez ensuite modifier la structure réelle via une référence d’interface, qui fait référence à l’object encadré.

    L’extrait de code suivant illustre ce que je viens de dire

     public interface IMyStructModifier { Ssortingng Name { set; } } public struct MyStruct : IMyStructModifier ... List obList = new List(); 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. Bonne question.
    Mise à jour: @Hath – Vous me faisais courir pour vérifier si j’avais oublié quelque chose d’aussi simple. (Ce serait incohérent si les propriétés et les méthodes de setter ne le faisaient pas – l’univers .Net est toujours équilibré 🙂
    La méthode Setter ne fonctionne pas
    obList2 [1] renvoie une copie dont l’état serait modifié. La structure originale dans la liste rest inchangée. Donc, Set-via-Interface semble être le seul moyen de le faire.

     List obList2 = new List(); 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); } 

    Ce n’est pas tant que les structures sont “immuables”.

    Le véritable problème sous-jacent est que les structs sont un type Value et non un type Reference. Donc, lorsque vous extrayez une “référence” à la structure de la liste, cela crée une nouvelle copie de la structure entière. Ainsi, les modifications que vous y apportez modifient la copie, et non la version originale de la liste.

    Comme le dit Andrew, vous devez remplacer la structure entière. À ce stade, je pense que vous devez vous demander pourquoi vous utilisez une structure en premier lieu (au lieu d’une classe). Assurez-vous de ne pas le faire avec des problèmes d’optimisation prématurés.

    Il n’y a rien de mal avec les structures qui ont des champs exposés ou qui autorisent la mutation via les méthodes de détermination des propriétés. Les structures qui se modifient en réponse à des méthodes ou à des getters de propriétés sont toutefois dangereuses car le système permettra aux méthodes ou aux getters de propriété d’être appelés sur des instances de structure temporaires. Si les méthodes ou les parsingurs apportent des modifications à la structure, ces modifications finiront par être éliminées.

    Malheureusement, comme vous le notez, les collections intégrées à .net sont vraiment faibles pour exposer les objects de type valeur contenus dans ces collections. Votre meilleur pari est généralement de faire quelque chose comme:

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

    Un peu ennuyeux, et pas du tout threadsafe. Toujours une amélioration par rapport à une liste de type de classe, où faire la même chose peut nécessiter:

       myList [1] .Name = "Albert";
    

    mais cela pourrait aussi nécessiter:

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

    ou peut-être

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

    ou peut-être une autre variante. On ne pourrait vraiment pas savoir à moins que l’on examine myClass ainsi que l’autre code qui place les choses dans la liste. Il est tout à fait possible que l’on ne puisse pas savoir si le premier formulaire est sûr sans examiner le code dans des assemblys auxquels on n’a pas access. En revanche, si Name est un champ exposé de MyStruct, la méthode que j’ai mise à jour pour le mettre à jour fonctionnera, indépendamment de ce que contient MyStruct, ou de ce que d’autres choses ont pu faire avec myList avant l’exécution du code ou faire avec elle après.