C# 循环内的委托如何理解局部变量和循环变量之间的差异
看看这段代码C# 循环内的委托如何理解局部变量和循环变量之间的差异,c#,loops,closures,C#,Loops,Closures,看看这段代码 List<Action> actions = new List<Action>(); for (int variable = 0; variable < 5; ++variable) { int myLocalVariable = variable; actions.Add(() => Console.WriteLine(myLocalVariable));
List<Action> actions = new List<Action>();
for (int variable = 0; variable < 5; ++variable)
{
int myLocalVariable = variable;
actions.Add(() => Console.WriteLine(myLocalVariable));
}
actions.ForEach(s => s.Invoke());
Console.ReadLine();
List actions=new List();
对于(int变量=0;变量<5;++变量)
{
int myLocalVariable=变量;
actions.Add(()=>Console.WriteLine(myLocalVariable));
}
actions.ForEach(s=>s.Invoke());
Console.ReadLine();
输出为01 2 3 4
查看IL代码,我倾向于认为编译器只创建了myLocalVariable的一个实例。这一事实也证实了在循环中使用局部变量的良好实践
那么,actions.Add()中的委托如何存储循环变量的“最新”版本呢
查看IL代码,我倾向于认为编译器只创建了myLocalVariable的一个实例
没有。C#语言规范清楚地表明,变量在循环的每次迭代中都会实例化——因此每次迭代都有一个单独的变量,并且它们被单独捕获
根据C#5规范第7.5.15.2节:
当执行进入局部变量的作用域时,该局部变量被认为是实例化的。例如,当调用下面的方法时,局部变量x被实例化并初始化三次,每次循环迭代一次
static void F() {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}
static void F(){
对于(int i=0;i<3;i++){
int x=i*2+1;
...
}
}
但是,将x的声明移到循环之外会导致x的单个实例化
未捕获时,无法准确观察局部变量实例化的频率,因为实例化的生命周期是不相交的,每个实例化都可能使用相同的存储位置。但是,当匿名函数捕获局部变量时,实例化的效果变得明显
查看IL代码,我倾向于认为编译器只创建了myLocalVariable的一个实例
没有。C#语言规范清楚地表明,变量在循环的每次迭代中都会实例化——因此每次迭代都有一个单独的变量,并且它们被单独捕获
根据C#5规范第7.5.15.2节:
当执行进入局部变量的作用域时,该局部变量被认为是实例化的。例如,当调用下面的方法时,局部变量x被实例化并初始化三次,每次循环迭代一次
static void F() {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}
static void F(){
对于(int i=0;i<3;i++){
int x=i*2+1;
...
}
}
但是,将x的声明移到循环之外会导致x的单个实例化
未捕获时,无法准确观察局部变量实例化的频率,因为实例化的生命周期是不相交的,每个实例化都可能使用相同的存储位置。但是,当匿名函数捕获局部变量时,实例化的效果变得明显
好的,请告诉我,如果我是对的,一个匿名函数捕获)局部实例化变量(myLocalVariable)的值,并在内部存储该值的副本,在这种情况下,它可以存储循环变量的值副本,那么匿名函数局部变量与循环变量的区别是什么@JonSkeet@VladimirGabrielyan:没有,因为循环变量被指定为只为for
循环实例化一次。对于foreach
循环,它曾经被实例化过一次,但对于C#5来说这是固定的,因此每次迭代都会被实例化。好的,请告诉我我是否正确,一个匿名函数捕获)局部实例化变量(myLocalVariable)的值,并在内部存储该值的副本,在这种情况下,它可以存储循环变量的值副本,那么匿名函数局部变量和循环变量的区别是什么呢@JonSkeet@VladimirGabrielyan:否,因为循环变量被指定为仅为for
循环实例化一次。对于foreach
循环,它曾经被实例化一次,但对于C#5来说这是固定的,因此每次迭代都会被实例化。