2009-03-26 3 views
0

私はこれが馬鹿だと知っています。しかし、私はここで間違って何かをしなければならない。リスト内の構造体の状態を変更できないのはなぜですか?

言って、その後どこか

struct lala 
{ 
    private bool state1; 

    public lala(bool state1) 
    { 
     this.state1 = state1; 
    } 

    public void SetState1ToTrue() 
    { 
     this.state1 = true; 
    } 

    public bool GetState1() 
    { 
     return this.state1; 
    } 
} 

...

List<lala> lalas = new List<lala>(); 

lalas.Add(new lala(false)); 
lalas.Add(new lala(false)); 

lalas[0].SetState1ToTrue(); 

// Why is it False??? 
Console.WriteLine(lalas[0].GetState1()); 

はそれを変更することを除き、これに回避策があります、ひどいunelegantと無駄に見えた

List<lala> lalas = new List<lala>(); 

lalas.Add(new lala(false)); 
lalas.Add(new lala(false)); 

lala newLala = lalas[0]; 
newLala.SetState1ToTrue(); 
lalas[0] = newLala; 

// It's True, finally. 
Console.WriteLine(lalas[0].GetState1()); 

2行のコード。もしLinq-ishやFunctional Programming-ishのようなものがあったら、1行のコードですばらしいでしょう。

+0

-1はコミュニティウィキです。 – Samuel

答えて

6

問題は、この行です。したがって、あなたのSetState1ToTrueはすぐに破棄されるlalaで動作し、リスト内のlalaは同じままです。それは、これを行うのと同じです:

lala newLala = lalas[0]; 
newLala.SetState1ToTrue(); 

それが参照型になるようにあなたは、ララクラスでない構造体を作る場合は、一時的な変数(明示的または暗黙的に)リスト内のララへの参照であります。

+0

+1。私はこれまでにこれまで実行してきましたが、この種の状況を引き起こす正確なセマンティクスを覚えていませんでした。これはまさにここで起こっていることです。これを行うには、希望の状態で新しい値を作成し、それをlalas [0]に格納する必要があります。 – jdmichal

0

あなたの問題は、参照型であるクラスではなく、値型である構造体を扱っていることです。期待している動作は参照型の動作です。宣言をクラスに変更することをお勧めします(単純な例を示します)、問題はないはずです。

lalas[0].SetState1ToTrue(); 

最初の部分は、lalas [0]、リストから最初のララを取得し、暗黙的変数に新しいコピーとしてそう:

1

構造体は値型なので、値渡しされます。つまり、lalas [0]はlalasに構造体のコピーを与えます。あなたはコピーを変更しているので、オリジナルは変更されません。

0

structは常に値型なので、本来不変です。これは、その代わりにやっての意味:

lalas[0].SetState1ToTrue(); 

あなたが行う必要があります。

lalas[0] = lalas[0].SetState1ToTrue(); 

を詳細に値型と参照型の違いについて説明しexcellent article by Jon Skeetがあります。

0

これをクラスに変更しないで(おそらく正解です)、Linq-ishのアプローチでは構造体を変更不可能にするため、 "状態変更"メソッドは代わりに変更されたバージョンを返します。そうすれば、間違って使うことはできません。

struct lala 
{ 
    private readonly bool state1; // note: readonly 

    public lala(bool state1) 
    { 
     this.state1 = state1; 
    } 

    public lala SetState1ToTrue() 
    { 
     return new lala(true); // would copy any other fields, unchanged 
    } 

    public bool GetState1() 
    { 
     return this.state1; 
    } 
} 

次に、あなたは一度の「変更」リスト全体をできます

List<lala> changed = original.Select(l => l.SetState1ToTrue()).ToList(); 

本当にあなたはブランドの新しいリストを作成しましたけれども - それはあなたのための構造体です。

+0

私はあなたの最後の点に同意しなければなりません。彼らが構造体であるという事実はあなたの最後のスニペットが新しいリストを作成することとは関係ありません。 – Samuel

+0

私はそれを非常にはっきりと説明しませんでした - 私は、リストだけでなく、リストのすべてのアイテムが新しいことを意味します。彼らがクラスであれば、リスト上の各アイテムを突然変異させることができます。 –

+0

これはかなり実行可能なソリューションのように思えますが、私はパフォーマンスが遅い側に少しあると予想します。それほど気にしない:p。 –

関連する問題