C# 在闭包中,什么触发捕获变量的新实例?

C# 在闭包中,什么触发捕获变量的新实例?,c#,closures,C#,Closures,我在读乔恩·斯基特的 在第156页,他有一个例子,清单5.13“用多个委托捕获多个变量实例化” 关于这个主题,我认为这本书可能做得更好的一件事是真正解释编译器在做什么,因为如果您理解编译器正在将封闭变量包装到一个新类中,那么所有这些“魔法”都是有意义的 请纠正我可能存在的任何误解或误解。另外,请随时详细说明和/或添加到我的解释中。听起来您已经找到了答案-您不会每次循环都得到一个新的索引。如果您考虑允许在循环内修改索引< /代码>值的方法,例如,如果您想跳过项目,在某些情况下将其设置为零,或者您

我在读乔恩·斯基特的

在第156页,他有一个例子,清单5.13“用多个委托捕获多个变量实例化”


关于这个主题,我认为这本书可能做得更好的一件事是真正解释编译器在做什么,因为如果您理解编译器正在将封闭变量包装到一个新类中,那么所有这些“魔法”都是有意义的


请纠正我可能存在的任何误解或误解。另外,请随时详细说明和/或添加到我的解释中。

听起来您已经找到了答案-您不会每次循环都得到一个新的
索引。如果您考虑允许在循环内修改<代码>索引< /代码>值的方法,例如,如果您想跳过项目,在某些情况下将其设置为零,或者您喜欢的任何其他东西,则可以增加它。应该清楚的是,您只有一个实例:<代码>索引< /代码>,而不是每次迭代都有一个新的实例。
另一方面,每次迭代都会创建一个新的
计数器
——如果您在循环的底部对其进行了更改,它将不会影响下一次迭代使用的
计数器
变量

foreach
循环用于重用其循环变量,其方式与
for
循环相同,这是人们常见的问题-请参阅


Eric Lippert说,他们在C#5中更改了foreach的
foreach
,每次都会得到一个新变量,而且就我所理解的闭包而言,他们将按原样离开
。匿名委托触发为委托代码块中涉及的变量创建类。考虑下面的代码:

class SomeClass
{
    public int counter;

    public void DoSomething()
    {
        Console.WriteLine(counter);
        counter++;
    }
}

//... 

List<ThreadStart> list = new List<ThreadStart>();

for (int index = 0; index < 5; index++)
{
    var instance  = new SomeClass { counter = index * 10 };
    list.Add(instance.DoSomething);
}

foreach (ThreadStart t in list)
{
    t();
}
class-SomeClass
{
公共int计数器;
公共无效剂量测定法()
{
控制台。写线(计数器);
计数器++;
}
}
//... 
列表=新列表();
对于(int-index=0;index<5;index++)
{
var instance=newsomeclass{counter=index*10};
list.Add(instance.DoSomething);
}
foreach(列表中的线程起始t)
{
t();
}

此代码与原始示例中的代码完全相同。变量
instance
是在for循环内部定义的,因此它的作用域在每次迭代时结束,但是垃圾收集器不会释放它,因为它被
list
引用。这就是在匿名委托的情况下创建类的原因。否则无法执行此操作。

Capture不会创建新变量。创建新变量的是计数器变量的声明。不,它们的范围不一样,我相信这就是乔恩想要展示的。每个循环计数器都超出范围,在本例中这是一件好事。但索引不能超出范围,否则您就没有什么可增量的了。我明白你的意思。这个问题本身就已经得到了回答……新实例的创建与其他任何情况相同。起初我真的很困惑,因为我认为<代码>计数器和<代码>索引>代码>在相同的范围内,直到我查看IL。@ RICHADESDRODE:除了查看IL,考虑查看语言规范,在第3.7节中清楚地说明了语言规范。for语句的for初始值设定项中声明的局部变量的作用域是for初始值设定项、for条件、for迭代器和for语句中包含的语句。“显然,在包含的语句中声明的变量的范围就是包含的语句本身。因此范围不同;嵌套的,是的,但不同。谢谢Eric。我想我需要为规范添加书签,以便快速引用。@RichardDesLonde:我的建议是你们两个下载Word文档表单,并获得一份带注释的打印规范“C#编程语言”。在我博客的侧栏中有一个链接。注释版有我、乔恩·斯基特、比尔·瓦格纳和更多人的有趣评论。
.locals init (
    [0] int32 length,
    [1] int32 i,
    [2] bool CS$4$0000
)

IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
IL_0004: ldc.i4.0
IL_0005: stloc.1
IL_0006: br.s IL_001b
// loop start (head: IL_001b)
    IL_0008: nop
    IL_0009: ldloca.s i
    IL_000b: call instance string [mscorlib]System.Int32::ToString()
    IL_0010: call void [mscorlib]System.Console::WriteLine(string)
    IL_0015: nop
    IL_0016: nop
    IL_0017: ldloc.1
    IL_0018: ldc.i4.1
    IL_0019: add
    IL_001a: stloc.1

    IL_001b: ldloc.1
    IL_001c: ldloc.0
    IL_001d: clt
    IL_001f: stloc.2
    IL_0020: ldloc.2
    IL_0021: brtrue.s IL_0008
// end loop
class SomeClass
{
    public int counter;

    public void DoSomething()
    {
        Console.WriteLine(counter);
        counter++;
    }
}

//... 

List<ThreadStart> list = new List<ThreadStart>();

for (int index = 0; index < 5; index++)
{
    var instance  = new SomeClass { counter = index * 10 };
    list.Add(instance.DoSomething);
}

foreach (ThreadStart t in list)
{
    t();
}