Adding method to delegate changes iteration in “fo

2019-06-14 19:32发布

问题:

This question already has an answer here:

  • How to tell a lambda function to capture a copy instead of a reference in C#? 4 answers

I've faced some issue with C# code. Adding method to delegate in "for" loop increments "i" by one., so "for(int i = 0, i < x ; i++)" must be change to "for(int i = -1, i < x-1; i++)" to work correctly. Why is that?

Code below throws an IndexOutOfRangeException

string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = 0; i < names.Length; i++)
{
    showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
    showName();
}

Right code is (look at iterator "i" which starts from -1 but "names[-1]" does not exist):

string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = -1; i < names.Length - 1; i++)
{
    showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
    showName();
}

This answer is correct (by Ed Plunkett): Each delegate references the variable i. They all reference the variable, so when they execute, they'll get whatever value it has right then. The delegates are executed after the for loop completes. At that point, i is equal to names.Length. Make a local copy of i in the body of the loop -- or use a foreach loop, which automatically fixes this issue.

回答1:

You should change your code like this;

for (int i = -1; i < names.Length - 1; i++)
{
    string name = names[i];
    showNameDelegate += () => global::System.Console.WriteLine(name);
}

Or you can try to use foreach.