delegateを知る
delegate使って、ちょっとおもしろいことを。
delegate内でループ変数jの値を使って、各フォームが閉じられた時に
targets[j].Flg = trueにしようとしてますが、
ループを抜けた後、このjは、j = 3をさすことになるので、
アクセス違反になってまいます。
そこで、一度targetsの参照クラスを用意して、そのクラスをdelegate内で
渡せば、うまくいくことになります。
この時ローカル変数を渡していることになり、C++,Cで組んできた人は、
混乱するかもしれませんが、ヘルパクラスをコンパイラが用意してくれるので
このコードは、エラーになりません。
1 namespace DisposeSample 2 { 3 using System; 4 using System.Collections; 5 using System.Windows.Forms; 6 using MbUnit.Framework; 7 8 /// <summary> 9 /// HogeHogeクラス 10 /// </summary> 11 class HogeHoge 12 { 13 private bool flg = false; 14 15 public HogeHoge(bool initFlg) 16 { 17 flg = initFlg; 18 } 19 20 public bool Flg 21 { 22 get { return flg; } 23 set { flg = value; } 24 } 25 } 26 27 class Program 28 { 29 private const int objNum = 3; 30 static void Main() 31 { 32 } 33 34 [TestFixture] 35 public class DelegateTest 36 { 37 [Test] 38 public void TestFunc() 39 { 40 HogeHoge targets = new HogeHoge[objNum]; 41 Form frms = new Form[targets.Length]; 42 for(int i = 0;i < targets.Length;i++) 43 targets[i] = new HogeHoge(false); 44 45 // --------------------------------------------------------- // 46 // テストその1 47 // --------------------------------------------------------- // 48 for(int j = 0;j < targets.Length;j++) 49 { 50 frms[j] = new Form(); 51 frms[j].Closed += delegate 52 { 53 // アクセスしようとしているインデックスを表示 54 MessageBox.Show("Index is " + j.ToString()); 55 if( j < targets.Length ) 56 targets[j].Flg = true; 57 }; 58 frms[j].KeyDown += delegate(object sender,KeyEventArgs e) 59 { 60 (sender as Form).Close(); 61 }; 62 frms[j].ShowDialog(); 63 } 64 TargetTest(targets); 65 66 // --------------------------------------------------------- // 67 // テストその2 68 // 69 // これは成功しない 70 // 71 // jがまだ生きていて、このjは、ループ終了後の3を指している。 72 // 当然、j = 3は、確保されていないのでアクセス不可能 73 // テストその3を実行する時は、コメントにしてください 74 // --------------------------------------------------------- // 75 #if TestDelegate 76 77 TargetInit(targets); 78 ShowForms(frms); 79 TargetTest(targets); 80 81 #endif 82 83 // --------------------------------------------------------- // 84 // テストその3 85 // --------------------------------------------------------- // 86 // delegateに渡す際に、インデックスを渡すと上記の不具合が 87 // 発生するので、以下のように参照オブジェクトを用意してあげるとよい 88 for(int k = 0;k < targets.Length;k++) 89 { 90 // 一時的に参照オブジェクトに入れてdelegateに渡す 91 // もしくは、基底クラス(Form)から派生して、 92 // 参照オブジェクトのメンバ(HogeHoge)をもたせるとか 93 HogeHoge temp = targets[k]; 94 frms[k].Closed += delegate { temp.Flg = true; }; 95 } 96 TargetInit(targets); 97 ShowForms(frms); 98 TargetTest(targets); 99 100 } 101 102 /// <summary> 103 /// ターゲットテスト 104 /// </summary> 105 /// <param name="targets"></param> 106 private void TargetTest(HogeHoge targets) 107 { 108 foreach(HogeHoge hoge in targets) 109 Assert.AreEqual(true,hoge.Flg); 110 } 111 112 /// <summary> 113 /// ターゲット初期化 114 /// </summary> 115 /// <param name="targets"></param> 116 private void TargetInit(HogeHoge targets) 117 { 118 foreach(HogeHoge target in targets) 119 target.Flg = false; 120 } 121 122 /// <summary> 123 /// フォーム表示 124 /// </summary> 125 /// <param name="frms"></param> 126 private void ShowForms(Form[] frms) 127 { 128 // もう一度表示 129 foreach(Form frm in frms) 130 frm.ShowDialog(); 131 } 132 } 133 } 134 }