C#对象引用和操作类型
我有一个关于C#中的C#对象引用和操作类型,c#,lambda,reference,C#,Lambda,Reference,我有一个关于C#中的Action类型和lambda的快速问题。下面是代码: static void Main(string[] args) { List<Action> actions = new List<Action>(); for (int I = 0; I < 10; I++) actions.Add(new Action(() => Print(I.ToString())));
Action
类型和lambda的快速问题。下面是代码:
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
for (int I = 0; I < 10; I++)
actions.Add(new Action(() => Print(I.ToString())));
foreach (Action a in actions)
{
a.Invoke();
}
actions.Clear();
int X;
for (X = 0; X < 10; X++)
{
int V = X;
actions.Add(new Action(() => Print(V.ToString())));
}
foreach (Action a in actions)
{
a.Invoke();
}
Console.ReadLine();
}
public static void Print(string s)
{
Console.WriteLine(s);
}
static void Main(字符串[]args)
{
列表操作=新建列表();
对于(int I=0;I<10;I++)
actions.Add(新操作(()=>Print(I.ToString()));
foreach(动作中的动作a)
{
a、 调用();
}
动作。清除();
int X;
对于(X=0;X<10;X++)
{
int V=X;
添加(新操作(()=>打印(V.ToString()));
}
foreach(动作中的动作a)
{
a、 调用();
}
Console.ReadLine();
}
公共静态无效打印(字符串s)
{
控制台。写入线(s);
}
如果运行此代码,您将看到它连续输出10到10次,然后第二次输出数字0-9。这显然与我使用X vs I的方式有关,以及我如何在第二个循环中每次给我的动作一个新变量V。。。可能每个新的V在内存中都是一个新地址,但我很难理解为什么I.ToString()在第一个循环中不做同样的事情。。。为什么第一个操作中使用的I.ToString()的工作方式与第二个示例的工作方式不一样?这是因为它只是一个委托,当您实际调用它时,它会被执行,并且在调用它时,所有操作都具有为
I
设置的最后一个值,而在foreach循环中,它会生成值的本地副本,因此每个操作都有自己的值,从而打印0-9
在第一个示例中,i
值在您第一次在foreach循环中调用委托时得到评估,此时i
中有10,在第二个示例中,您将该值存储在一个本地中,该本地模拟foreach循环所做的相同行为,as foreach循环还生成值的本地副本
你也可以阅读,他在那里链接到eric lippert的两篇文章,这将对你有更多帮助。编译器有效地扩展了
for
循环:
{
int I;
for (I = 0; I < 10; I++)
{
actions.Add(new Action(() => Print(I.ToString())));
}
}
{
int I;
对于(I=0;I<10;I++)
{
actions.Add(新操作(()=>Print(I.ToString()));
}
}
这意味着所有lambda实例都捕获了相同的I
实例,当循环退出时,该实例将为10
在第二个示例中,您将该值复制到一个变量中,该变量的作用域为for
语句的主体,lambda将捕获该局部变量。循环的每次重复都会有一个唯一的局部变量
重要的是要认识到,您并不是捕获变量的值,而是捕获变量本身。这就是为什么第一个示例不起作用,而第二个示例起作用。当在第一个循环中创建
操作时,真正保存的是对Print()
方法的调用,直到调用Invoke()
方法,才获得变量I
的值,但这发生在循环完成且变量I
的值为10之后
在第二种情况下,您在每次迭代中创建一个新变量V
,这样当您执行操作时,每个变量都会被调用,并使用在该迭代中创建的变量V
的值。这可能会有所帮助:感谢您的解释。我本以为I.ToString()正在生成一个新变量,但显然不是这样。更像是函数调用I.ToString()被存储,I的值可能会发生更改,直到调用时才进行计算。这是一个比公认答案更好的解释。