Dispatcher.BeginInvoke exception in an array loop

216 Views Asked by At

I have the follow piece of code that loop through an array, where the array element stores a file name. Per loop, the code load an XML document. When I call the array element directly I receive an exception that says index was outside the boundary of array, but if I store the array element to a separate variable, the code compile just fine.

I just cannot understand why there is a difference, and why one work but not the other.

Compile 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);
            }));
    }
}

Exception: Index was outside the boundary of array

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);
            }));
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

The issue is caused by "variable capture", it uses the final value of i not the value at the time you called it. To fix the problem make a local variable inside of the loop and use that instead.

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);
            }));
    }
}
0
On

Basically this is a known behavior of Captured variables. They are outer variables used by lambda expression / statement. These types of lambda expressions / statements are called Closures. As we all know there is delayed execution of lambda expression. While being executed, they use the current value of the captured variable rather than the value when they were created.

In order to solve this problem of closure, there is a universal remedy. Whenever we need to capture a variable in a closure, we must be making a local copy of the variable by declaring a local variable in lambda and assigning the value of captured variable to this local variable.