【お勉強記録】C#文法学び直し。イベント
イベント
Visual Studioによって、特に考えることなく、イベント機能を使っていましたが、 イベントはあらかじめ、メソッドの参照オブジェクトを保有しておくことで、機能を実現しているようです。
イベントは発生を監視するイベントループと、イベント発生した時に実際に処理されるイベントハンドラで成り立っています。
delegateで実現できるイベントですが、C#ではさらにイベントに特化したeventキーワードが用意されています。
eventで宣言されたデリゲートは、同じクラスからのみ呼び出しはできないが、外からデリゲートにメソッドを追加できるという特徴を持っています。
using System; namespace test { class Counter { public event EventHandler ThresholdReached; protected virtual void OnThresholdReached(EventArgs e) { EventHandler handler = ThresholdReached; if (handler != null) { handler(this, e); } } public void Start() { System.Threading.Thread.Sleep(5000); if (ThresholdReached != null) { //"ThresholdReached"イベントの発生 ThresholdReached(this, EventArgs.Empty); } } } class Program { static void Main(string[] args) { Counter c = new Counter(); c.ThresholdReached += c_ThresholdReached; c.Start(); Console.ReadLine(); } static void c_ThresholdReached(object sender, EventArgs e) { Console.WriteLine("5秒経った後に実行"); } } }
イベントって、observerパターンに近い感じがしますね。
デザインパターンとかもしっかり勉強して、自分の中に蓄積させていきたいですねー
【お勉強記録】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でいいのでしょうか?