【C#】「C#は参照型でも値(プリミティブ)型でも値渡し」

はじめに

・「参照型渡すときにrefパラメータ修飾子つける意味あんの?」

・「参照型でも値(プリミティブ)型でも値渡し」→「??」

C#のパラメータ修飾子について学んでいるときに、
上記の疑問がわいたので調べた内容をまとめた記事です。



これ↓って参照渡しじゃないよ。

void Test()
{
    List<Hoge> a = new List<Hoge>();
    Val(a);
    Debug.Log("count = " + a.Count);
}

private void Val(List<Hoge> b)
{
    b.Add(new Hoge());
}

▼実行結果

count = 1

上記のソースで「countが増えてる=参照渡しだ」と判断していたのですが、
参照渡しではなく値渡しです。

参照型の値渡し

上記のソースでは、
・参照型変数aはListの参照先を保持した変数です。
・参照型変数aを値渡しします。
値渡しをするということは、参照型変数aの値=Listの参照 をコピーします
コピーされた変数が参照型変数bです。
Val()の中で、参照型変数bの値=Listの参照 を元にListにAddします。Listのカウント数は1になりました。
Test()の中で、参照型変数aの値=Listの参照 を元にListのカウント数をデバッグ出力します。

ということが行われています。

参照型変数abが持つ参照の参照先のListは同じなのですが、それぞれで参照をもっているということです。

以下のようなイメージです。

f:id:snoopopo:20190317095633p:plain

参照型の「参照渡し」

一方、refを用いて「参照渡し」した場合は、
同じ参照を参照型変数abも持つことになります。

以下のようなイメージです。

f:id:snoopopo:20190317100231p:plain

結果が異なるパターン

先程のソースでは実行結果が同じだったので、実行結果が異なる例を挙げます。

void Test()
{
    List<Hoge> a = new List<Hoge>();
    Ref(ref a);
    //Val(a); RefかValのどちらか呼ぶ
    Debug.Log("count = " + a.Count);
}

private void Val(List<Hoge> b)
{
    b = new List<Hoge>();
    b.Add(new Hoge());
}

private void Ref(ref List<Hoge> b)
{
    b = new List<Hoge>();
    b.Add(new Hoge());
}

Ref()(参照渡し)を呼んだときの実行結果

count = 1

Val()(値渡し)を呼んだときの実行結果

count = 0

このように結果が異なります。


先程、値渡しをした場合はコピーされ、
変数a,bそれぞれで参照をもっていると書きました。

‘Val()‘ の中で変数bが持っている参照の参照先が新しくnewされたListに変わります。
変数aの参照先は変わりません。
Test()では変数aの参照先をデバッグ出力しているので、カウント数は0のままになります。

以下のようなイメージです。

f:id:snoopopo:20190317101426j:plain


次に参照渡しの場合です。
参照渡しの場合は変数abがもっている参照は同一です。

‘Val()‘ の中で変数bが持っている参照の参照先が新しくnewされたListに変わります。
変数aと変数bが持っている参照は同一なので、変数aの参照先も新しくnewされたListに変わります。

以下のようなイメージです。

f:id:snoopopo:20190317102337j:plain

最後に

このように、参照型の値渡しと参照渡しとでは動きが異なります。

最初に疑問に思ったことの回答・・・

「参照型渡すときにrefパラメータ修飾子つける意味あんの?」

→ある。無駄なコピーはなくせるのでrefはつけた方がいい。

だけど無駄なコピーなくすってメリットぐらいしか思いつかん。。(※)
ほかにメリットある??

(※)今回例であげたような、
呼び出し先のメソッドでnew されるのが前提のソースの場合は、
呼び出し元でnewせずパラメータ修飾子もrefじゃなくてoutでもらうべきだと思うからです。

参考

参考にさせてもらいました、あざしたー★!

teratail.com

sorasorasora.hatenablog.com