参照渡し?値渡し?
よくわかっていなかったので調べました。
参考記事
値渡し
C#(というか多くの言語)では通常、メソッドの引数へは値渡しとなる。
値渡しとは変数の値をコピーしてメソッドの引数に渡すこと。
なので値を渡した変数をメソッド内で変更しても、元の変数は変化しない。
public static void Add(int x) { x += 10; Console.WriteLine(x); // 10 } static void Main(string[] args) { int x = 10; Add(x); Console.WriteLine(x); // 10 }
参照の値渡し
先ほどの例は値型だが、 参照型をメソッドに渡すときも値渡しである。
参照型の場合、変数の参照値をコピーしてメソッドの引数に渡している
これを参照渡しと間違いやすいようだが、実際には参照の値渡しである。
メソッドの変数には呼び出し元の変数を指す参照値が入っているので、Add
すると呼び出し元の変数もorange
が追加される。
public static void Foo(List<string> words) { words.Add("orange"); words.ForEach(Console.WriteLine); } static void Main(string[] args) { var words = new List<string> { "apple", "banana" }; Foo(words); Console.WriteLine("-----"); words.ForEach(Console.WriteLine); }
出力結果
apple banana orange ----- apple banana orange
words
に入っているのはあくまでも参照値のコピーなので、メソッド内で新たなインスタンスを代入し、操作を行っても呼び出し元には影響しない。
public static void Foo(List<string> words) { words = new List<string>(); words.Add("orange"); words.ForEach(Console.WriteLine); } static void Main(string[] args) { var words = new List<string> { "apple", "banana" }; Foo(words); Console.WriteLine("-----"); words.ForEach(Console.WriteLine); }
出力結果
orange ----- apple banana
参照渡し
PythonやJavaには値渡しのみで参照渡しはないが、C#にはちゃんと参照渡しが存在する。
参照渡しは変数の参照をメソッドの引数に渡している。※コピーではない
参照の値渡しでは不可能だったが、参照渡しは呼び出し元の変数をメソッド内で操作するのと同じことなので、新しいインスタンスを代入するとそれも呼び出し元に反映される。
呼び出し元、メソッドの引数の前にref
を指定することで参照渡しになる。
public static void Foo(ref List<string> words) { words = new List<string>(); words.Add("orange"); words.ForEach(Console.WriteLine); } static void Main(string[] args) { var words = new List<string> { "apple", "banana" }; Foo(ref words); Console.WriteLine("-----"); words.ForEach(Console.WriteLine); }
出力結果
orange ----- orange
終わり。