C# C语言中的闭包lambda表达式#
我有这种功能C# C语言中的闭包lambda表达式#,c#,lambda,closures,C#,Lambda,Closures,我有这种功能 function SomeFunction() { const int NUMBER_OF_CONCURENT_THREADS = 50; List<Guid> sessions = new List<Guid>(); ManualResetEvent[] doneEvents = new ManualResetEvent[NUMBER_OF_CONCURENT_THREADS]; Action<int>
function SomeFunction()
{
const int NUMBER_OF_CONCURENT_THREADS = 50;
List<Guid> sessions = new List<Guid>();
ManualResetEvent[] doneEvents = new ManualResetEvent[NUMBER_OF_CONCURENT_THREADS];
Action<int> makeServiceCall = (iter) =>
{
var proxy = GetProxy();
sessions.Add(proxy.GetCurrentSessionId());
doneEvents[iter].Set();
};
for (int i = 0; i < NUMBER_OF_CONCURENT_THREADS; ++i)
{
doneEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((o) =>
{
int iter = i;
makeServiceCall(iter);
});
}
WaitHandle.WaitAll(doneEvents);
Assert.AreEqual(50, sessions.Count);
}
function SomeFunction()
{
const int concurrent线程数=50;
列表会话=新列表();
ManualResetEvent[]DoneeEvents=新的ManualResetEvent[并发线程数];
Action makeServiceCall=(iter)=>
{
var proxy=GetProxy();
sessions.Add(proxy.GetCurrentSessionId());
doneEvents[iter].Set();
};
for(int i=0;i<并发线程数;++i)
{
doneEvents[i]=新的手动重置事件(false);
ThreadPool.QueueUserWorkItem((o)=>
{
int iter=i;
makeServiceCall(iter);
});
}
WaitHandle.WaitAll(doneEvents);
Assert.AreEqual(50,sessions.Count);
}
问题是,在
doneEvents[iter].Set()时,我得到了IndexOutOfRangeException
代码>代码行。请问,有什么办法可以解决吗?啊,迭代器变量上的好的ol'闭包;p
移动int iter
:
int iter = i;
ThreadPool.QueueUserWorkItem((o) => {
makeServiceCall(iter);
});
当前,您正在捕获随着循环而变化的内容,并且通常在线程启动时在循环之后。或者,使用argo
:
ThreadPool.QueueUserWorkItem((o) => {
int iter = (int)o;
makeServiceCall(iter);
}, i);
这将在项目排队时传递i
的盒装副本,因此它不会更改
如果问题不清楚:捕获到lambda中的变量保留其原始声明点——这是一个完整的词汇闭包。QueueUserWorkItem
中的i
不是“创建此lambda时i
的值”,而是“现在i
的值”。在大多数情况下,for
循环的速度将大大超过线程的创建/拾取速度,因此当线程开始时,for
循环已经完成,i
的值现在超出了数组的界限。Eric Lippert写了一篇关于关闭循环变量的伟大文章。过来看