レガシーコードからの脱却

レガシーな職場でも独学でどうにか頑張っていくブログです。

【お勉強記録】C#文法学び直し。ref

参照渡し

メソッドに引数を渡すときに値ではなく引数の参照を渡すことができます。 メソッドと呼び出し側双方ともに「ref」をつけることで参照渡しであると明示します。 呼び出し側でrefと書くのは知らないうちに参照渡しになっていて、値が書き換えられているといったようなことを防ぐためのようです。

using System;

namespace test
{
    class Program
    {
        delegate void Greet();

        static void Main(string[] args)
        {
            int a = 100;
            Console.WriteLine(a.ToString());
            Program.Test(ref a);
            Console.WriteLine(a.ToString());

            Console.ReadLine();
        }   

        static void Test(ref int reference)
        {
            reference= 10;
        }

    }
    
}

実装結果をみると直接aが書き換えられているのがわかります。

100
10

refを使うことで、複数の戻り値をもつメソッドを実現できます。

using System;

namespace test
{
    class Program
    {
        delegate void Greet();

        static void Main(string[] args)
        {
            //参照渡しのため値初期化必要
            int kotae = 0;
            int amari = 0;
            Program.Dev(3, 2, ref kotae, ref amari);
            Console.WriteLine("答え・・・" + kotae.ToString() + " あまり・・・" + amari.ToString());

            Console.ReadLine();
        }

        static void Dev(int left, int right, ref int kotae, ref int amari)
        {
            kotae = left / right;
            amari = left % right;
        }

    }

}

実行結果

答え・・・1 あまり・・・1

refを使うことで複数の戻り値を持つメソッドを実現できました。 ただし、C#では返すだけの目的で引数を使用する場合のために「out」が用意されています。

先ほどのサンプルをoutで書き換えた結果は以下のようになります。

using System;

namespace test
{
    class Program
    {
        delegate void Greet();

        static void Main(string[] args)
        {
            //初期化の必要なし
            int kotae;
            int amari;
            Program.Dev(3, 2, out kotae, out amari);
            Console.WriteLine("答え・・・" + kotae.ToString() + " あまり・・・" + amari.ToString());

            Console.ReadLine();
        }

        static void Dev(int left, int right, out int kotae, out int amari)
        {
            kotae = left / right;
            amari = left % right;
        }

    }

}

kotae、amariともに値を返すためのものなので、「out」を使ってます。 先ほどは呼び出し型で設定する引数の初期化が必要でしたが、今回は値を設定しないでもコンパイル可能です。 (refだとコンパイルエラー)

うーん…使い分けとしては、メソッド内でも引数の値を使いたい場合はref戻したいだけの時はoutでいいのでしょうか?

【お勉強記録】C#文法学び直し。マルチキャストデリゲート

マルチキャストデリゲート

デリゲートオブジェクトは複数のメソッドを管理することも可能で、それをマルチキャストデリゲートと呼ぶそうです。

using System;

namespace test
{
    class Program
    {
        delegate void Greet();

        static void Main(string[] args)
        {
            //インスタンス生成
            Morning morning = new Morning();
            Noon noon = new Noon();
            Evening evening = new Evening();
            //マルチキャストデリゲート
            Greet greet = new Greet(morning.SayGoodMorning);
            greet += new Greet(noon.SayHello);
            //暗黙変換
            greet += evening.SayGoodEvening;

            greet();

            Console.ReadLine();
        }        
    }
    class Morning
    {        
        public void SayGoodMorning() 
        {
            Console.WriteLine("Good Morning!");
        }
    }

    class Noon
    {
        public void SayHello()
        {
            Console.WriteLine("Hello!");
        }
    }

    class Evening
    {
        public void SayGoodEvening()
        {
            Console.WriteLine("Good Evening!");
        }
    }
}

実行結果を見ると「おはよう」から「こんばんは」まで順(シーケンシャル)に実行メソッドが呼び出されているのがわかります。

Good Morning!
Hello!
Good Evening!

「+=」で追加しています。ちなみに削除は「-=」でできます。

で、このマルチキャストデリゲートがどのようなところで使われているかなのですが、 イベントの通知など、複数のイベントハンドラに通知する必要がある際や、コールバックのような動きを実現できます。 (『Effective C#4.0』第3章 項目24 P.133)