2014-01-16 2 views
3

Предположат, у меня есть следующий код:Избежание сбежавших значений в затворах

for(int i=0;i<10;i++) 
{ 
    //"i" is captured in the closure passed to LazyCreate 
    MyApi.AddLazyCreate(() => new foo(/*other params*/ i)); 
} 

Это приведет к непреднамеренному поведению, так как «я» буду 10 для всех добавленных замыканий.

Есть ли безопасный способ избежать этого? , например. если я создаю свой api, используя Expression<func<foo>> , если каждый «AddLazyCreate» проверяет переданное выражение и сохраняет копии этих значений, тогда должно быть возможно достичь намеченного поведения, не так ли? , то есть я должен скомпилировать каждый аргумент из выражения и получить временное значение аргумента и воссоздать новое выражение, используя оцененные аргументы. (выражение всегда будет «новым» выражением)

Или я пропустил что-то фундаментальное здесь? Являются ли те рекказы, где я по-прежнему получаю странное поведение?

+0

Согласно Эрику, это будет «исправлено» на C# 5 http://blogs.msdn.com/b/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part-two .aspx – Maarten

+1

@Maarten Только в петлях foreach. Для циклов все еще фиксируется последний результат. – TylerD87

+0

@ TylerD87 Я стою исправлено :-) – Maarten

ответ

4

Вы можете просто сделать это:

for(int i=0; i<10; i++) 
{ 
    int number = i; 
    MyApi.AddLazyCreate(() => new foo(/*other params*/ number)); 
} 

Это приведет к тому, что оно захватит разное количество на каждой итерации цикла.

+0

omg как я мог пропустить это!?, Это поведение изменилось с более ранних версий .NET?, Я уверен, что единственный способ сделать это - создать закрытие в это собственная функция, закрывающая функцию args –

+0

@RogerAlsing Nope, это сработало с момента появления лямбда. – svick

Смежные вопросы