Help us understand the problem. What is going on with this article?

C# out と ref

More than 3 years have passed since last update.

C#のoutrefというパラメーター修飾子についてのメモ


どちらも参照渡しのためのパラメーター修飾子です。

out

out修飾子はreturn以外でメソッド内からメソッド外へデータを受け渡す場合で使用されます。

よく使われるものとしてはTryParseメソッドがあります。

// outの受け皿
int number;

// int.TryParseは結果として成否を返すが、成功の場合は変換結果がnumberへ格納される
bool result = int.TryParse("1234", out number)

ref

ref修飾子はメソッド外からメソッド内へデータを渡し、変更を外部へ反映させる必要がある場合に使用します。

void Main()
{
    int x = 10;
    Console.WriteLine(x); // 10;

    Hoge(x);
    Console.WriteLine(x); // 20;
}

void Hoge(ref int x)
{
    x = x + 10;
}

制限

out修飾子のついたパラメーターはメソッド内で必ず代入をする必要があります。

NG
int Hoge(out int x)
{
    return 0;
}
OK
int Hoge(out int x)
{
    x = 10;
    return 0;
}

ref修飾子のついたパラメーターはメソッドに渡す前に必ず初期化する必要があります。

NG
void Hoge()
{
    int x;
    Piyo(ref x);
}

void Piyo(ref int x)
{
    x += 10;
}
OK
void Hoge()
{
    int x = 0;
    Piyo(ref x);
}

void Piyo(ref int x)
{
    x += 10;
}

オーバーロード

outrefメソッド シグネチャの一部とは見なされません。
そのため、outrefの違いでのオーバーロードは定義できません。

NG
void Hoge(out int x) { }

void Hoge(ref int x) { }

outrefのついていないパラメーターとoutrefが付いているパラメーターでのオーバーロードは可能です。

OK
void Hoge(int x) { }

void Hoge(out int x) { }

asyncとの併用は不可

async修飾子のついたメソッドには使用できません。

NG
async void Hoge(out int x) { }

async void Piyo(ref int x) { }

Iteratorメソッドには使用不可

yield returnyield breakを含むIteratorメソッドには使用できません。

NG
IEnumerable<int> Hoge(out int x)
{
    for (var i = 0; i < 10; i++)
    {
        x = i;
        yield return i;
    }
}

IEnumerable<int> Piyo(ref int x)
{
    var min = x;
    var max = x + 10;
    for (var i = min; i < max; i++)
    {
        x = i;
        yield return i;
    }
}

参照型の参照渡し

値型を参照渡しする際はあまり難しいことを考えなくても良いと思うのですが、参照型を参照渡しした場合は少々分かりづらい気がします。

まず次のようなクラスがある場合

Person.cs
class Person
{
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    public string Name { get; set; }
    public int Age { get; set; }
}

クラスは参照型なので、普通にメソッドのパラメーターとして渡した場合はメソッド内部でメンバーを変更されてもメソッド外のインスタンスに反映されます。

Program.cs
void Hoge(Person p)
{
    p.Age += 10;
}

void Main()
{
    // Age = 20 で初期化
    var p = new Person("John", 20);

    // Ageに10足す
    Hoge(p);

    // 反映される
    Console.WriteLine($"Name={p.Name}, Age={p.Age}"); // Name=John, Age=30
}

しかし、次のようにメソッド内で引数として渡された変数自体に代入を行った場合は、メソッド外へ影響が反映されません。

Program.cs
void Hoge(Person p)
{
    p = new Person("Mike", 33);
    p.Age += 10;
}

void Main()
{
    // Age = 20 で初期化
    var p = new Person("John", 20);

    // p に新しいインスタンスを代入し、Ageに10足す
    Hoge(p);

    // 反映されない
    Console.WriteLine($"Name={p.Name}, Age={p.Age}"); // Name=John, Age=20
}

これをrefにするとメソッド内で代入を行った結果も反映されます。

Program.cs
void Hoge(ref Person p)
{
    p = new Person("Mike", 33);
    p.Age += 10;
}

void Main()
{
    // Age = 20 で初期化
    var p = new Person("John", 20);

    // p に新しいインスタンスを代入し、Ageに10足す
    Hoge(ref p);

    // 反映される
    Console.WriteLine($"Name={p.Name}, Age={p.Age}"); // Name=Mike, Age=43
}

終わり

TryParseのようなoutの使い方はコードが簡潔になりますが、outにしろrefにしろ濫用すると何処で値が書き換わったか、いつ参照先が変更されたか、などが追いにくくなるため極力使用しないほうが良いでしょう。

参考

out (C# リファレンス)
ref (C# リファレンス)

muro
自分が記憶喪失になったとき用に書きます。なので当たり前な情報も書きます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした