如何告诉lambda函数捕获副本而不是C#中的参考?

发布于 2025-02-14 01:14:01 字数 626 浏览 1 评论 0原文

我一直在学习C#,并且正在尝试了解Lambdas。在下面的样本中,它打印出10次十次。

class Program
{
    delegate void Action();
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i )
            actions.Add(()=>Console.WriteLine(i));

        foreach (Action a in actions)
            a();
    }
}

显然,Lambda背后的生成类是存储指向int i变量的指针,并且每次循环迭代时,都将新值分配给同一参考。有没有办法强迫LAMDA抓住副本,例如C ++ 0x语法

[&](){ ... } // Capture by reference

Vs。

[=](){ ... } // Capture copies

I've been learning C#, and I'm trying to understand lambdas. In this sample below, it prints out 10 ten times.

class Program
{
    delegate void Action();
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i )
            actions.Add(()=>Console.WriteLine(i));

        foreach (Action a in actions)
            a();
    }
}

Obviously, the generated class behind the lambda is storing a reference or pointer to the int i variable, and is assigning a new value to the same reference every time the loop iterates. Is there a way to force the lamda to grab a copy instead, like the C++0x syntax

[&](){ ... } // Capture by reference

vs.

[=](){ ... } // Capture copies

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

把人绕傻吧 2025-02-21 01:14:01

我唯一能够找到的解决方案是首先制作本地副本:

for (int i = 0; i < 10; ++i)
{
    int copy = i;
    actions.Add(() => Console.WriteLine(copy));
}

但是我很难理解为什么将副本放入前面的副本与让lambda Capture i 有什么不同。

The only solution I've been able to find is to make a local copy first:

for (int i = 0; i < 10; ++i)
{
    int copy = i;
    actions.Add(() => Console.WriteLine(copy));
}

But I'm having trouble understanding why putting a copy inside the for-loop is any different than having the lambda capture i.

玩套路吗 2025-02-21 01:14:01

编译器正在做的是将您的lambda和lambda捕获的任何变量捕获到编译器生成的嵌套类中。

编译后,您的示例看起来很像:

class Program
{
        delegate void Action();
        static void Main(string[] args)
        {
                List<Action> actions = new List<Action>();

                DisplayClass1 displayClass1 = new DisplayClass1();
                for (displayClass1.i = 0; displayClass1.i < 10; ++displayClass1.i )
                        actions.Add(new Action(displayClass1.Lambda));

                foreach (Action a in actions)
                        a();
        }

        class DisplayClass1
        {
                int i;
                void Lambda()
                {
                        Console.WriteLine(i);
                }
        }
}

通过在for循环中制作副本,编译器会在每个迭代中生成新对象,例如:

for (int i = 0; i < 10; ++i)
{
    DisplayClass1 displayClass1 = new DisplayClass1();
    displayClass1.i = i;
    actions.Add(new Action(displayClass1.Lambda));
}

What the compiler is doing is pulling your lambda and any variables captured by the lambda into a compiler generated nested class.

After compilation your example looks a lot like this:

class Program
{
        delegate void Action();
        static void Main(string[] args)
        {
                List<Action> actions = new List<Action>();

                DisplayClass1 displayClass1 = new DisplayClass1();
                for (displayClass1.i = 0; displayClass1.i < 10; ++displayClass1.i )
                        actions.Add(new Action(displayClass1.Lambda));

                foreach (Action a in actions)
                        a();
        }

        class DisplayClass1
        {
                int i;
                void Lambda()
                {
                        Console.WriteLine(i);
                }
        }
}

By making a copy within the for loop, the compiler generates new objects in each iteration, like so:

for (int i = 0; i < 10; ++i)
{
    DisplayClass1 displayClass1 = new DisplayClass1();
    displayClass1.i = i;
    actions.Add(new Action(displayClass1.Lambda));
}
执笔绘流年 2025-02-21 01:14:01

唯一的解决方案是在lambda中进行本地副本和参考。 c#(和vb.net)中的所有变量在闭合中访问时,都将具有参考语义与复制/值语义。用两种语言都无法改变这种行为。

注意:它实际上并未作为参考编译。编译器将变量提升为封闭类,并将“ I”的访问重定向给定关闭类内部的字段“ I”。不过,通常将其视为参考语义通常更容易。

The only solution is to make a local copy and reference that within the lambda. All variables in C# (and VB.Net) when accessed in a closure will have reference semantics vs. copy/value semantics. There is no way to change this behavior in either language.

Note: It doesn't actually compile as a reference. The compiler hoists the variable into a closure class and redirects accesses of "i" into a field "i" inside the given closure class. It's often easier to think of it as reference semantics though.

哀由 2025-02-21 01:14:01

请记住,lambda表达实际上只是匿名方法的句法糖。

话虽如此,您真正寻找的是匿名方法如何在父范围内使用本地变量。

这是描述这一点的链接。 http://www.codeproxpt:/

Remember that lambda expressions are really only syntactic sugar for anonymous methods.

That being said, what you are really looking for is how anonymous methods use local variables in a parent scope.

Here's a link describing this. http://www.codeproject.com/KB/cs/InsideAnonymousMethods.aspx#4

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文