2011-09-02 13 views
9

Powiel możliwe:
Modify Struct variable in a DictionaryPrzypisanie pól/właściwości w struct

Dlaczego jest tak, że

MyStruct test = new MyStruct(); 
    test.Closed = true; 

Działa świetnie, ale

MyDictionary[key].Closed = true; 

Pokazuje błąd "Nie można zmodyfikować wyrażenie, ponieważ nie jest zmienna" podczas kompilacji?

Czym różni się przypisanie w tych dwóch przypadkach?

Uwaga: MyDictionary jest typu <int, MyStruct>

Kod struct:

public struct MyStruct 
{ 
    //Other variables 
    public bool Isclosed; 
    public bool Closed 
    { 
     get { return Isclosed; } 
     set { Isclosed = value; } 
    } 
//Constructors 
} 
+0

Pokaż więcej kodu .. – Zabba

+0

@Zabba, edytowane dla więcej kodu. – soandos

+0

Komentarze do głosowania proszę? – soandos

Odpowiedz

12

ponieważ MyDictionary[key] powraca struct, to jest naprawdę przekazujących kopię obiektu w kolekcji, a nie rzeczywisty obiekt, co dzieje się podczas korzystania z klasy. Właśnie o tym ostrzega kompilator.

Aby obejść ten problem, trzeba będzie ponownie ustawić MyDictionary[key], może tak:

var tempObj = MyDictionary[key]; 
tempObj.Closed = true; 
MyDictionary[key] = tempObj; 
+0

Ale wtedy musiałbym ponownie zadzwonić do całego konstruktora? Nie ma sposobu, aby zmienić część struktury w tej sytuacji? – soandos

+0

Zmodyfikowałem mój przykład, aby ponownie użyć tego samego obiektu zamiast tworzyć nowy. – Keith

+1

@soandos struct jest zawsze kopiowany, gdy jest przekazywany między metodami, więc "cały konstruktor" dzieje się cały czas (na przykład kiedy uzyskujesz dostęp do swojej struktury przez klucz w tym dict), to dlaczego nie zaleca się aby mieć strukturę większą niż 16 bajtów –

1

Zmiana struct być klasa zamiast ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     dic = new Dictionary<int, MyStruct>(); 

     MyStruct s = new MyStruct(){ Isclosed=false}; 

     dic.Add(1,s); 

     dic[1].Isclosed = true; 

     Console.WriteLine(dic[1].Isclosed.ToString()); //will print out true... 
     Console.Read(); 
    } 

    static Dictionary<int, MyStruct> dic; 

    public class MyStruct 
    { 
     public bool Isclosed; 
     public bool Closed 
     { 
      get { return Isclosed; } 
      set { Isclosed = value; } 
     } 
    } 
} 
+0

Wiem, że structs są bardziej wydajne, gdy mamy do czynienia z kilkoma obiektami, które zasadniczo zawierają pola takie jak twoja struktura, ale jeśli zdarzy ci się tylko utworzyć instancję kilku obiektów, to utworzenie klasy pozwoli ci zaoszczędzić trochę linii kodu :) –

+0

Podczas korzystania z odsłoniętej struktury pola z wbudowanymi kolekcjami innymi niż tablice, należy skopiować strukturę, zmodyfikować ją, a następnie zapisać. Uciążliwość, ale semantyka jest przewidywalna; 'dic [1] .Isclosed' będzie zawsze niezależny od' dic [0] .Isclosed'. Powiedzenie 'dic [0] = dic [1];' skopiuje stan 'dic [0]' bez dołączania dwóch elementów razem. Jeśli używa się zmiennej klasy, można napisać 'dic [1] .Isclosed = true;' ale to nie oznacza, że ​​spowoduje to pożądane zachowanie. Obiekt, który hermetyzuje swój stan w stanach zmiennego obiektu przechowywanego w kolekcji, musi ... – supercat

+0

... generalnie unikać sytuacji, w której jakiekolwiek odwołania do przedmiotowych obiektów sięgają poza kod.Oznacza to defensywne kopiowanie wszelkich przychodzących danych, które mają być przechowywane w zbiorze, oraz defensywne kopiowanie lub zawijanie wszelkich odczytanych z niego danych. Struktury automatycznie wykonują defensywne kopiowanie podczas odczytu lub zapisu danych, ale operacje kopiowania na strukturze dowolnej wielkości są znacznie tańsze niż operacje na klasie o tej samej wielkości. Różnica w kosztach jest największa w przypadku małych struktur, ale pozostaje znacząca, dopóki struktura nie stanie się bardzo duża. – supercat