Impossible de changer la valeur des membres de struct dans les collections génériques

Imaginez cette struct :

  struct Person { public ssortingng FirstName { get; set; } public ssortingng LastName { get; set; } } 

Et le code suivant:

  var list = new List(); list.Add(new Person { FirstName = "F1", LastName = "L1" }); list.Add(new Person { FirstName = "F2", LastName = "L2" }); list.Add(new Person { FirstName = "F3", LastName = "L3" }); // Can't modify the expression because it's not a variable list[1].FirstName = "F22"; 

Quand je veux changer la valeur de Property , cela me donne l’erreur suivante:

 Can't modify the expression because it's not a variable 

Bien que, lorsque j’ai essayé de le changer dans un tableau tel que Person[] cela fonctionnait sans erreur. Y at-il un problème avec mon code lors de l’utilisation de collections génériques?

Lorsque vous renvoyez la struct via l’indexeur List[] , une copie de l’entrée est renvoyée. Donc, si vous FirstName le FirstName ici, il sera simplement jeté. D’où l’erreur du compilateur.

Réécrivez votre Person pour qu’elle soit une class type référence ou effectuez une réaffectation complète:

 Person person = list[1]; person.FirstName = "F22"; list[1] = person; 

De manière générale, les structures modifiables provoquent des problèmes tels que ceux qui peuvent causer des maux de tête à l’avenir. Sauf si vous avez une très bonne raison de les utiliser, vous devriez sérieusement envisager de changer votre type de Person .

Pourquoi les structures mutables sont-elles «mauvaises»?

De toute évidence, une partie de la question est toujours sans réponse. Quelle est la différence entre List et Person[] . En terme d’obtention élément par index, l’indexeur d’appels List (méthode) renvoie une copie de l’instance de type valeur. Inversement , tableau par index ne renvoie pas une copie mais un pointeur géré sur l’élément situé à l’index (instruction IL spéciale ldelema utilisée ).

Bien sûr, les types de valeurs mutables sont diaboliques, comme mentionné dans d’autres réponses. Regardez l’exemple simple.

 var en = new {Ints = new List{1,2,3}.GetEnumerator()}; while(en.Ints.MoveNext()) { Console.WriteLine(x.Ints.Current); } 

Surpris?

Refaites votre struct comme telle:

  struct Person { private readonly ssortingng firstName; private readonly ssortingng lastName; public Person(ssortingng firstName, ssortingng lastName) { this.firstName = firstName; this.lastName = lastName; } public ssortingng FirstName { get { return this.firstName; } } public ssortingng LastName { get { return this.lastName; } } } 

Et code suivant comme:

  var list = new List(); list.Add(new Person("F1", "L1")); list.Add(new Person("F2", "L2")); list.Add(new Person("F3", "L3")); // Can modify the expression because it's a new instance list[1] = new Person("F22", list[1].LastName); 

Ceci est dû à la sémantique de copie de struct . Rendez-le immuable, respectez ces contraintes et le problème disparaîtra.