C#のメソッドでの値渡しと参照渡しについて

C#のメソッド呼び出しをする際に引数を渡してメソッド内で引数の値を使う事は多々あります。

メソッド呼び出し時の引数の渡し方には「値渡し」と「参照渡し」の二通りの方法があるので、今回はそれについて勉強していきます。

後述する引数に付けるキーワードのrefとoutを使う頻度は少ないかも?しれません。

Unityの場合はPhysics.Raycastの引数でoutが出てきたりするので意味を理解しておくと何をしているのか?がわかります。

スポンサーリンク

変数の種類

メソッドに渡す引数の渡し方の前に、変数の種類について少し見ていきます。

変数については、

Unityでゲームを作る時に必要なC#の変数について勉強します。

を見てください。

変数には値型と参照型があり、値型は値そのもの、参照型は値がある場所を指し示す参照値が入っています。

値型の変数を引数で渡す

値型と参照型の変数の違いがわかったところでメソッド呼び出し時に値型の変数を渡して変数の値がどうなるのかを見てみましょう。

値型であるint型の変数intValueに1を入れた後、IncreaseメソッドにintValueを引数として渡して呼び出します。

IncreaseメソッドはintValueに引数として渡ってきた値を入れ、それに1を足してその値を呼び出し元に返しています。

Unityのコンソールには結果として

2
1

が表示されます。

Increaseの呼び出しから得られた戻り値は2で、Increase呼出し後にintValueの値を表示すると1が表示されていることになります。

この場合は値型の変数をそのまま引数で指定している為、引数は値渡し(変数の値のコピー)をしていて、Increase呼出しの後StartメソッドでintValueの値を表示してもintValueの値は変わっていません。

StartとIncreaseで同じ名前のintValueを使っていますが、これはまったく別物です。

参照型の変数を引数に渡す

次に参照型の変数をメソッド呼び出し時に引数として渡してみます。

参照型であるint型の配列を宣言し、最初に要素を表示しています。

その後ChangeArrayValueメソッドにintArrayを引数として渡し、その後intArrayの要素を再度表示しています。

ChangeArrayValueの引数には参照型であるintArrayを渡しているので、引数としては値の場所を示す参照値が渡っています。

ChangeArrayValueメソッドではtempIntArrayにintArrayの参照値を受け取り、配列の0番目の要素を5に書き換えます。

その為StartメソッドでChangeArrayValueを呼び出した後にintArrayの要素を表示すると

5
1
2
3

と表示されます。

値型と違って参照型の場合は値がある場所を指し示す参照値が渡っている為、ChangeArrayValueメソッドで要素の書き換えが起こるとStartメソッド内のintArrayの値も書き換わってしまいます。

refを使った参照渡し

値型と参照型の変数を引数に渡す違いが見れましたが、refを使うと明示的に参照渡しをすることが出来ます。

例えば値型の変数を引数として渡す時に渡す引数の前にrefを書きます。

RefTestは最初に示したPassByValueスクリプトのメソッド呼び出し時の実引数とメソッドの仮引数にrefを付けただけです。

結果として表示されるのは

2
2

となります。

refを付けてintValueを渡しているのでintValueの参照値がIncreaseに渡されその値を書き換えているのでStartメソッド内のintValueも書き換えられます。

上の例ではIncreaseで戻り値を返していますが参照で渡ってきた値を書き換えている為、特に値を返す必要がありません。

outを使った参照渡し

refと似たようなものにoutを使った参照渡しがあります。

outを使った引数は参照渡しになり、呼び出し先のメソッドで初期化をする必要があります。

先ほど作成したRefTest2スクリプトをrefからoutに変更してみます。

RefTest2のスクリプトのrefをoutにし、Startメソッド内のintValueの初期化をなくし、Increaseメソッド内でintValueの初期化をしています。

Increaseの呼び出し時に渡すintValueにoutが付いているのでStartメソッド内でのintValueの初期化をしません。

IncreaseメソッドのintValueにもoutを付け、intValueの初期化をしその値をインクリメントしています。

Increaseメソッド呼び出し時の引数intValueにはoutキーワードが付いているので参照渡しとなりIncreaseで戻り値を返さなくてもStartメソッド内のintValueの値が変更されます。

上のスクリプトでは11がコンソールに表示されます。

OutTest1では値型の変数を参照渡しにしていますが、参照変数の場合もそのまま参照渡しになります。

StartメソッドではTestClassの変数testClassの宣言をするだけで実体は生成せずIncreaseメソッドにout付きの引数として渡します。

Increaseメソッド内でTestClassの実体を作成しプロパティのAgeに10を入れた後インクリメントします。

このスクリプトを実行するとコンソールに11が表示されます。

この例はこの記事の最初に示したPhysics.Raycastの例と使い方としては同じ感じですね。

終わりに

参照渡しをする際に使用するrefとoutについてはPhysics.Raycastの引数等で見ていたのでなんとなく何をしているのかはわかっていましたが、refやoutが実際にどういった動作をするのかを見ていけたのでよかったです。

わたくしが持っている本

ではrefやoutを使ったメソッドはほとんど使う必要がない事が書かれていましたし、個人的に使う事もなかったので動作がどんなものなのかがわかるだけでいいかなと思いました。

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます

コメント

  1. junshimura より:

    refを用いて参照型を渡すメリットは処理結果を戻り値を複数の変数にしたい場合に有効になります。returnで返せるのは値型か参照を返す形になりますが、複数の値を返したい場合は関数内でnewしたオブジェクトの参照を返すことになり、その分のメモリが無駄になりえます。