アレがアレでアレ

(できれば)プログラミング関係のことを書きたい

参照渡し?値渡し?

よくわかっていなかったので調べました。

参考記事

qiita.com

値渡し

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

参照渡し

PythonJavaには値渡しのみで参照渡しはないが、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

終わり。