グレインの備忘録

プログラミング関係とかをつらつらと。

構造体のDictionaryでは直接値を変更できない

コンテナの返値が値型か参照型かに気をつけましょうねという話。

シチュエーション

例えば、以下のようなコードを書いてみたとする。

public class Program
{
    struct MyStruct
    {
        public int val1;
        public int val2;
    }
    
    public static void Main()
    {
        var dic = new Dictionary<int, MyStruct>();
        
        dic[0].val1 = 1;
        dic[0].val2 = 2;
    }
}

自前の構造体をDictionaryに格納し、その値を変更するコードである。

しかし、これはコンパイルエラーになる。

error CS1612: 変数ではないため、'Dictionary.this[int]' の戻り値を変更できません

Dictionary内の要素に値を代入することができていないようだ。

dic[0]の返値は参照型ではなく値型

実は、これはMyStructが値型であることが原因である。

つまり、dic[0]というのは、dic内の0番目の要素のコピーであって、それに対していかなる操作を行ってもdic内の要素には一切影響しない。

上記のように[]で参照したものの値を直接書き換えたいならば、MyStructをclassにするしかない。

public class Program
{
    class MyStruct
    {
        public int val1;
        public int val2;
    }
    
    public static void Main()
    {
        var dic = new Dictionary<int, MyStruct>();
        
        dic.Add(0, new MyStruct());

        dic[0].val1 = 1;
        dic[0].val2 = 2;
    }
}

これならdic[0]はdic内の0番目の要素への参照となり、正しく動く。


C++ならコンテナは必ず参照型を返してくれるので、原因が分かるのに時間がかかった。