Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#对象引用和操作类型_C#_Lambda_Reference - Fatal编程技术网

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())));

我有一个关于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())));

        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的值可能会发生更改,直到调用时才进行计算。这是一个比公认答案更好的解释。