【C#】in / out / ref パラメータ修飾子

パラメータとは、引数のことです。

C#の引数には in, out, ref というパラメータ修飾子をつけることができます。

今回の記事は、パラメータ修飾子それぞれの機能ついて

パラメータ修飾子をつけない場合

C#では、値(プリミティブ)型でも参照型でも「値渡し」になります。

詳しくはこちら↓

www.snoopopo.com

ref パラメータ

refをつけると参照渡しになる。

private void Test()
{
    int a = 0;
    Poyo(ref a);
    Debug.Log(a); //出力結果は1になる
}
    
private void Poyo(ref int a){
    a = 1;
}

out パラメータ

outをつけると、呼ばれた側のメソッドで代入しなければいけない=代入されることが保証される。
もちろん、値渡しにするとそれが実現できないので、参照渡しになる。

private void Test(){
    int a; //初期化する必要なし
    Poyo(out a); //outはつけないとだめ。
}

private void Poyo(out int a){
    a = 1; //代入する必要がある
}

渡すときにoutつけるので、渡す側のメソッドでは変数に値が代入されることが呼ばれる側のメソッドの定義を見なくても一目でわかる。

outパラメータはint.TryParse()のように渡したパラメータに結果を詰める、
みたいなメソッドでよく使われる。

int result; //初期化の必要はない
int.TryParse(input, out result);
Debug.Log(result);

渡したList型に値を詰めるメソッドとかはよくあると思うので、そういう時もoutパラメータが有効。

List result;
Poyo(out result);

c# 7.0 からは以下のように省略する書き方もできるようになった。

  • c# 7.0以降▼
int.TryParse(input, out int result); //省略した書き方
Debug.Log(result);

in パラメータ

inパラメータはC#7で追加された。

読み取り専用の引数になります。

読み取り専用なので、inパラメータがついたメソッドを呼ぶ前に必ず値を代入しておく必要があります。

  • 呼ぶ側
int a;
Val(a); //aの値が代入されてないのでコンパイルエラー
int b = 1;
Val(b);  //OK
Val(100); //直に定数渡すのもOK

呼ばれるメソッド側では引数に値を代入することはできなります。
これによって勝手に書き換えられるようなことがなくなることが保証される。

  • 値型の場合
private void Val(in int b)
{
    b = b++; //コンパイルエラー
}
  • 参照型の場合
private void Ref(in List<Hoge> list)
{
    list = new List<Hoge>(); //コンパイルエラー
    list.Add(new Hoge()); //これは問題なし
}

参照型の場合は、参照型の変数の値=実体の参照を変えることができない、
つまり新しい参照を代入する=newすることはできません。
これによって、今までrefで書くことができていた以下のような処理を防ぐことができる。

以下のソースはrefで渡された参照型変数にnewすることが呼び出されたメソッド側でできてしまい、
呼び出し側のメソッドが知らないうちに参照が書き換えることができる状態だった。
inを使えばnewされることがないのでこれを防ぐことができる。

private void Ref(ref List<Hoge> list)
{
    list = new List<Hoge>();
}

inパラメータがもっている参照が示す参照先のオブジェクトを操ることはできるので、

C#7を使うには

unityでC#7を使うには、

Edit > ProjectSettings > Player > Scripting Runtime Version

.NET 4.x Equivalentにすることで使えるようになる。

f:id:snoopopo:20190324224630p:plain