2016-12-27 10 views
1

配列要素がファイル名を格納する配列をループするコードを次に示します。ループごとに、コードはXMLドキュメントをロードします。配列要素を直接呼び出すと、indexが配列の境界の外側にあるという例外が発生しますが、配列要素を別の変数に格納すると、コードは正常にコンパイルされます。配列ループ内のDispatcher.BeginInvoke例外

私はちょうど違いがある理由と、なぜ1つが他のものではないのかを理解できません。

コンパイルOK

for(int i =0; i < MyArray.Count(); i++) 
{ 
    string myString = MyArray[i].Split(',')[0]; 

    Dispatcher.BeginInvoke(new Action(() => 
      { 
       string xmlPath = _PATH + + myString; 
       var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo); 
      })); 
    } 
} 

例外:インデックスが配列の境界外では

for(int i =0; i < MyArray.Count(); i++) 
{ 
    Dispatcher.BeginInvoke(new Action(() => 
      { 
       string xmlPath = _PATH + + MyArray[i].Split(',')[0]; 
       var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo); 
      })); 
    } 
} 
+0

コンソールにすべての 'i'値を書き込もうとしますか? –

+0

あなたの 'MyArray'はどのように見えますか? –

答えて

2

問題は、 "変数捕捉" によって引き起こされ、それがiの最終的な値を使用していますあなたがそれを呼び出した時の値ではありません。問題を修正するには、ループの内部にローカル変数を作成し、代わりにその変数を使用します。

for(int i =0; i < MyArray.Count(); i++) 
{ 
    int j = i; 
    Dispatcher.BeginInvoke(new Action(() => 
      { 
       string xmlPath = _PATH + + MyArray[j].Split(',')[0]; 
       var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo); 
      })); 
    } 
} 
2

これは、キャプチャされた変数の既知の動作です。ラムダ式/ステートメントで使用される外部変数です。これらのタイプのラムダ式/ステートメントはClosuresと呼ばれます。我々が知っているように、ラムダ式の実行が遅れています。実行中は、作成されたときの値ではなく、キャプチャされた変数の現在の値が使用されます。

この閉鎖の問題を解決するために、普遍的な救済策があります。クロージャーで変数を取得する必要があるときは、ラムダでローカル変数を宣言し、キャプチャされた変数の値をこのローカル変数に割り当てることによって、変数のローカルコピーを作成する必要があります。