2010-09-24 4 views
3
namespace MyNamespace 
{ 
    public struct MyStruct 
    { 
     public string MyString; 
     public int MyInt; 
     public bool MyBool; 
    } 

    public class MyClass 
    { 
     private List<MyStruct> MyPrivateVariable; 

     public List<MyStruct> MyVariable 
     { 
      get 
      { 
       if (MyPrivateVariable == null) 
       { 
        MyPrivateVariable = new List<MyStruct>(); 

        MyPrivateVariable.Add(new MyStruct()); 
        MyPrivateVariable.Add(new MyStruct()); 
       } 

       return MyPrivateVariable; 
      } 
     } 

     public void MyLoop() 
     { 
      foreach (MyStruct ms in MyVariable) 
      { 
       // Doesn't compile, but it works if you execute it through the Immediate window, or in Quickwatch 
       ms.MyBool = false; 

       // Compiles, works 
       MyFunction(ms); 
      } 
     } 

     public void MyFunction(MyStruct ms) 
     { 
      ms.MyBool = false; 
     } 
    } 
} 

Des explications raisonnables pour cela?Foreach struct étrange erreur de compilation en C#

Le rendement du compilateur:

Error: Cannot modify members of 'ms' because it is 'foreach iteration variable'

EDIT:

question supplémentaire:

Je viens essayé de changer une chaîne de MyFunction, et il ne met pas à jour réellement ms. MAIS: Si je vais sur quickwatch et que j'y assigne la même valeur, cela met à jour ms. Pourquoi cela se produit-il s'il ne devrait même pas être compilé en premier lieu, ne devrait pas lancer une exception?

EDIT2:

Ok, montre rapide travaille également sur une copie de ms, c'est pourquoi je peux modifier sa valeur, il ne modifie pas réellement le contenu de MyPrivateVariable.

+0

Quelle est l'erreur du compilateur? –

+0

Que dit le message du compilateur? – CodingGorilla

+0

quel est le message d'erreur du compilateur? – EJC

Répondre

6

a Struct sémantique de type valeur. Ainsi, toute modification apportée à l'instance de struct n'affecterait pas l'instance d'origine. Le compilateur C# essaie de vous en avertir.

5

C# n'itéère pas les structures par référence dans le fichier "foreach (MyStruct ms ...)" donc ms dans ce contexte est immuable.

Remplacez MyStruct par une classe à la place. QuickWatch peut manipuler les types de valeur sur la pile.

+0

Parfois, il peut être utile d'enrouler une structure mutable dans une classe 'Holder ' à champ exposé simple pour l'utiliser dans certaines situations, mais remplacer simplement une structure mutable par une classe mutable pour faciliter la mutation des objets dans les collections est une mauvaise idée.En général, chaque objet mutable devrait avoir exactement un autre objet qui encapsule son état mutable. Si l'on veut copier quelque chose d'un 'List >' vers un emplacement existant dans un autre, 'List2 [1] .Value = List1 [3] .Value;'. Pour ajouter un élément de liste à une autre liste, dites 'List2.Add (nouveau Holder (Liste1 [3]))'. – supercat

1

car struct est valuetype et non un type de référence. Si MyStruct était une classe, elle aurait été compilée sans problèmes. vérifier this fil pour plus de détails.

0

Vous ne pouvez pas modifier les références d'une variable d'itération: vous ne pouvez pas pointer la variable vers une autre instance (pour savoir pourquoi, voir Why is The Iteration Variable in a C# foreach statement read-only?).

'Modification' un struct (un type de valeur) crée une nouvelle instance du type, de sorte que la déclaration ms.MyBool = false est dénuée de sens.

L'appel à MyFunction(ms) compile parce qu'il fonctionne sur une copie de ms (bien qu'il ne peut toujours pas faire ce que vous pourriez attendre).

+0

alors pourquoi puis-je les modifier dans Quick Watch? Peu importe, cela fonctionne aussi sur une copie de la structure, pourquoi existe-t-il des structures? – bevacqua

+1

@Nico: Les structs ont un but, mais les structures * mutables * ne le font presque jamais. –

+1

@Nico: Tout ce que vous faites est de modifier une copie qui sera ensuite jetée. C'est essentiellement un non-op. –