我一直在看这段代码。我意识到这总是抛出notsupportedexception的原因是因为temp总是等于20;但是,我希望有人向我解释为什么temp总是等于20而不是在循环中设置为temp的值。
{
delegate int Del(int i);
static event Del MyEvent;
static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
MyEvent += a =>
{
int temp = i;
if (a != temp) throw new NotSupportedException();
return a * 2;
};
Console.WriteLine("C'est fini");
Console.WriteLine(GetValue(5));
Console.ReadLine();
}
static int GetValue(int arg)
{
foreach(Del myEvent in MyEvent.GetInvocationList())
{
try
{
return myEvent(arg);
}
catch(NotSupportedException)
{
continue;
}
}
throw new NotSupportedException();
}
}
答案 0 :(得分:6)
在您的处理程序定义中,您将关闭循环变量i
,而不是i
的当前值,因此当您到达循环结束时,i = 20
在所有已注册处理程序。您可以通过将i
复制到另一个循环变量来修复它:
for (int i = 0; i < 20; i++)
{
int temp = i;
MyEvent += a =>
{
if (a != temp) throw new NotSupportedException();
return a * 2;
};
}
答案 1 :(得分:4)
i
正在封闭中使用。你有这个循环:
for (int i = 0; i < 20; i++)
MyEvent += a =>
{
int temp = i;
if (a != temp) throw new NotSupportedException();
return a * 2;
};
lambda使用i
,而不是 i 的值。换句话说,您在这里创建的代理实际上是指循环正在更改的变量i 。解决这个问题的一个简单方法是使用局部变量来强制闭包捕获一个未被修改的变量:
for (int i = 0; i < 20; i++)
{
var value = i;
MyEvent += a =>
{
int temp = value;
if (a != temp) throw new NotSupportedException();
return a * 2;
};
}
乍一看,您可能认为这并不能解决您的问题。但是局部变量value
实际上是每次迭代的不同变量。当在闭包中捕获该变量时,它不会被循环更新。
答案 2 :(得分:2)
只需将temp
移到闭包之外。
for (int i = 0; i < 20; i++)
{
int temp = i;
MyEvent += a =>
{
if (a != temp) throw new NotSupportedException();
return a * 2;
};
}
答案 3 :(得分:1)
for (int i = 0; i < 20; i++)
MyEvent += a =>
{
int temp = i;
if (a != temp) throw new NotSupportedException();
return a * 2;
};
我希望有人向我解释为什么temp总是等于20而不是在循环中设置为temp的值。
问题是,temp
未设置为 循环中的任何内容。你正在做的是声明一个新的匿名方法(使用args => {}
语法或lambda表达式)。
然后,您的MyEvent
委托会汇总指向您所有20个新匿名方法的指针。
在您触发事件之前,这些方法不会被执行,这发生在这一行:
return myEvent(arg);
到那时,i
为20.所以temp
也是20。