LoginSignup
3
4

More than 5 years have passed since last update.

dynamic 経由の値型の取り回し

Posted at

どーいうことだってばよ?

例えば、以下のような構造体(値型)をこさえたとして、


struct SomeStruct
{
    public int Value { get; set; }
    public override string ToString() => $"Value is {Value}";
}

コレを、dynamic経由で取り回したときどうなるかというのが今回のお題。
最後までおつきあい頂ければこれ幸いナリ。

複数のdynamicに値型経由で代入する場合

コレは割と直感的な結果になると思う。
以下のようなコードを書いたとする。



internal static void Main()
{
    var val = new SomeStruct {Value = 42};
    dynamic dynamA = val;
    dynamic dynamB = val;


    //Value is 42
    Console.WriteLine(dynamA.ToString());

    //Value is 42
    Console.WriteLine(dynamB.ToString());


    dynamA.Value = 114514;

    Console.WriteLine();
    //Value is 114514
    Console.WriteLine(dynamA.ToString());

    //Value is 42
    Console.WriteLine(dynamB.ToString());
}

この場合、コメントに記載したとおりの出力となる。
このようになる理由は、dynamic DynamA=val;及びdynamic DynamB=val;は、共々Valのコピーをボクシングしているので、片方のValueを動かしてももう片方が影響を受けることは無い。

複数のdynamicにobject経由で代入する場合

こちらは若干直感的ではないかも知れない。

同様にコードを書いていこう


internal static void Main()
{
    object obj = new SomeStruct {Value = 42};
    dynamic dynamA = obj;
    dynamic dynamB = obj;


    //Value is 42
    Console.WriteLine(dynamA.ToString());

    //Value is 42
    Console.WriteLine(dynamB.ToString());


    dynamA.Value = 114514;

    Console.WriteLine();
    //Value is 114514
    Console.WriteLine(dynamA.ToString());

    //Value is 114514
    Console.WriteLine(dynamB.ToString());
}

この場合、dynamAのValueに新たな値を代入した場合、dynamBも同様に値が変更されている。
これは、元がobject型なので、ボクシングが最初から行われており、そのボクシングされた結果の参照先をdynamAdynamBが参照することになるので、参照型のような振る舞いをすることになる。
また、このことからdynamic型の動的呼び出しは外から観測する限り、ボクシングしたまま値型の内部状態を変更可能であると言うことになると思う。

参考まで、下記のようなコードもobject経由の代入と同じ挙動をとる。


internal static void Main()
{
    dynamic dynamA = new SomeStruct {Value = 42};
    dynamic dynamB = dynamA;


    //Value is 42
    Console.WriteLine(dynamA.ToString());

    //Value is 42
    Console.WriteLine(dynamB.ToString());


    dynamA.Value = 114514;

    Console.WriteLine();
    //Value is 114514
    Console.WriteLine(dynamA.ToString());

    //Value is 114514
    Console.WriteLine(dynamB.ToString());
}

まとめ

代入の差異が挙動に直結するので、このようなことをする際は若干注意が必要かと思いまとめてみました。
特に、object経由の場合は、一般的な値型の振る舞いと異なり、参照型のそれに近い形になるので、意図的に使う場合は別として、注意をしなければならないと考えます。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4