在委托声明中引用i是否有效?
targets[i].PingReply = e.Reply;
它是否会引用
中定义的相同数组元素pingSender.SendAsync( targets[i].IPAddress, targets[i].Timeout);
或者当委托人解雇时,我的价值是不同的?我问,因为我在PingCompleted中得到的索引越界,i = 3,我不知道为什么。
public void Ping(PingTest[] targets)
{
var finished = new CountdownEvent(targets.Count());
for (int i = 0; i < targets.Count(); i++)
{
finished.AddCount();
var pingSender = new Ping();
pingSender.PingCompleted += (sender, e) =>
{
targets[i].PingReply = e.Reply;
finished.Signal();
};
pingSender.SendAsync(targets[i].IPAddress, targets[i].Timeout);
}
finished.Signal();
finished.Wait();
}
这是电话......
var pingTests = new PingTest[]
{
new PingTest("Router", new IPAddress(new byte[] {192, 168, 1, 8}), 2),
new PingTest("Exchange", new IPAddress(new byte[] {192, 168, 1, 78}), 3),
new PingTest("SQL", new IPAddress(new byte[] {192, 168, 1, 99}), 3)
};
netwrkService.Ping(pingTests);
答案 0 :(得分:5)
您希望这个程序片段做什么?
int i = 0;
Func<int> f = ()=>i;
i = 3;
Console.WriteLine(f());
试试吧。它做了你认为应该做的事吗?
匿名函数关闭变量,而不是变量过去的值。当您调用lambda时,循环变量不再具有创建委托时所执行的值。
有关详细信息,请参阅http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/。
答案 1 :(得分:3)
在C#中,closures close over variables, not over values。在for
循环中,只有一个变量i
,当每个PingCompleted
处理程序读取i
的值时,它会获得当前该单个变量的值,而不是处理程序连接时返回的i
的值。因此,如果处理程序在for
循环结束后执行,那么i
将等于3 - 而不是您想要的!
要解决此问题,请将i
的值复制到循环内声明的另一个变量中,然后更改处理程序以使用该新变量:
for (int i = 0; i < targets.Count(); i++)
{
...
int j = i;
pingSender.PingCompleted += (sender, e) =>
{
targets[j].PingReply = e.Reply; // <== j, not i
finished.Signal();
};
在循环中声明变量时,每次迭代都会逻辑地创建变量的新实例。因此,PingCompleted
处理程序现在引用j
的不同实例,每个实例都包含该处理程序的正确索引。
答案 2 :(得分:0)
由于循环在PingCompleted被调用之前完成,因此当第一次调用PingCompleted时,i增加到3。然后它再被调用两次(因为这是你的for循环初始化我仍然在3,因为for循环已经完成并且不再增加i。
你明白为什么我总是出界吗?您的索引i在第一次迭代时从0变为1,在第二次迭代时从1变为2,在最后一次迭代时变为2到3(在结束时设置为3)。完成所有迭代后,首先调用PingCompleted,索引已经为3。