Starry

プログラミングやクラウドについて

C# ref修飾子, out修飾子

C#のout修飾子、ref修飾子はメソッド使用時に参照を渡すことを目的としている。
いくつか例を示す。
まずはクラスの準備。

class Student
{
    public Student(int Id, string Name, int ScoreJapanese, int ScoreMath, int ScoreEnglish, int ClassNumber)
    {
        this.Id = Id;
        this.Name = Name;
        this.ScoreJapanese = ScoreJapanese;
        this.ScoreMath = ScoreMath;
        this.ScoreEnglish = ScoreEnglish;
        this.ClassNumber = ClassNumber;
     }
     public int Id { get; set; }
     public string Name { get; set; }
     public int ScoreJapanese { get; set; }
     public int ScoreMath { get; set; }
     public int ScoreEnglish { get; set; }
     public int ClassNumber { get; set; }
}


次にStudent型のの変数を用意し、メソッドに入れてstudentのみ値を変える。

static void Main(string[] args)
{
    var student = new Student(1, "taro", 82, 71, 75, 1);
    Console.WriteLine(student.Name + ":" + student.Id);
    classSub(student);
    Console.WriteLine(student.Name + ":" + student.Id);
}

public static void classSub(Student student)
{
    student.Id = 2;
}

結果はstudentのidは2に変わる。
このようにメソッドに値を渡し、その値を変更した時元の値にも
影響を及ぼすことを参照渡しという。
通常の引数となると、値は変わることはない。


例えば次のような例であればstudentの値は変わらない。

static void Main(string[] args)
{
    var student = new Student(1, "taro", 82, 71, 75, 1);
    Console.WriteLine(student.Name + ":" + student.Id);
    classSub2(student);
    Console.WriteLine(student.Name + ":" + student.Id);
}

public static void classSub2(Student student)
{
    student = new Student(2, "taro", 82, 71, 75, 1);
}


ここで無理やり参照渡しにするのがout修飾子とref修飾子だ。
以下のように使う。
ref修飾子。

static void Main(string[] args)
{
    var student = new Student(1, "taro", 82, 71, 75, 1);
    Console.WriteLine(student.Name + ":" + student.Id);
    refSub1(ref student);
    Console.WriteLine(student.Name + ":" + student.Id);
}

public static void refSub1(ref Student student)
{
    student = new Student(2, "taro", 82, 71, 75, 1);
}

out修飾子

static void Main(string[] args)
{
    var student = new Student(1, "taro", 82, 71, 75, 1);
    Console.WriteLine(student.Name + ":" + student.Id);
    outSub1(out student);
    Console.WriteLine(student.Name + ":" + student.Id);
}

public static void outSub1(out Student student)
{
    student = new Student(2, "taro", 82, 71, 75, 1);
}

違いは大してないような気がするがoutSub1で使ってるoutのついてる引数は
メソッド内で何かしらの値を割り当てられることが必要。
と、ここまで説明してきたけど、正直あまり使わない方がいいような修飾子ではある。


ただし、これを使ってるint.TryParseメソッドやDictionary.TryGetValueメソッドというものがあるので
ある程度は知っておいた方がいいかな、と。
int.TryParseメソッド

int.TryParse("123", out var number);
Console.WriteLine(number);

パースとはもちろんキャストのことだがこの場合はstringの123をintに変換する。
さらに第2引数にoutを入れることによってnumberという変数を宣言しつつ123をキャストした結果を格納できる。
キャストに成功すれば、Trueを返し失敗すれば Falseを返す。
Dictionary.TryGetvalueメソッド

dict.Add("田中", "たなか");
Console.WriteLine(dict.TryGetValue("鈴木", out var value));
Console.WriteLine(value);
Console.WriteLine(dict.TryGetValue("田中", out var value2));
Console.WriteLine(value2);

C#のDictionary型はkeyが存在しない場合例外が発生してしまう。
なので、TryGetValueによってkeyがあるか確かめつつ値を確認することが重要。
これも上のTryParseメソッドと同様にkeyがあるかを確認し、あった場合はvalueに格納。
さらに値があった場合はTrueを返す。なければFalseを返す。

参考URL
https://qiita.com/muro/items/f88b17b5fea3b4537ba7