C# 闭包变量作用域

标签 c# .net

关于闭包如何应用变量范围的(另一个?)问题。这是一个最小的例子:

public class Foo
{
    public string name;
    public Foo(string name)
    {
        this.name = name;
    }
}


public class Program
{
    static Action getAction(Foo obj)
    {
        return () => Console.WriteLine(obj.name); 
    }

    static void Main(string[] args)
    {
        Foo obj1 = new Foo("x1");    
        Action a = getAction(obj1);  
        obj1 = new Foo("x2");        
        a();                         
    }
}

这会打印出 x1。可以解释为:

getAction 返回一个匿名函数,它有一个包含变量 obj 的闭包。 objobj1 具有相同的引用 value 但它与 obj1 的关系到此为止,因为闭包仅包含 对象。换句话说,obj1 之后取的任何值都不会影响闭包。因此无论何时/无论如何 a 被调用(例如 a 被传递给其他一些函数)它总是打印 x1

现在我的问题是:

  1. 以上解释是否正确?
  2. 我没有想到具体的场景,但如果我们希望程序打印 x2(例如闭包以包含外部范围)怎么办?可以完成吗(或者甚至尝试都没有意义)?

最佳答案

让我们考虑一下:

static Action getAction(Foo obj)
{
    return () => Console.WriteLine(obj.name); 
}

闭包覆盖了参数 obj;此 obj 是按值传递的引用,因此如果调用者这样做:

x = someA();
var action = getAction(x);
x = someB(); // not seen by action

然后闭包仍然在 原始 值之上,因为引用(不是对象)在传递给 getAction 时被复制

请注意,如果调用者更改原始对象的值,方法将看到:

x = someA();
var action = getAction(x);
x.name = "something else"; // seen by action

getAction 方法内部,它基本上是:

var tmp = new SomeCompilerGeneratedType();
tmp.obj = obj;
return new Action(tmp.SomeCompilerGeneratedMethod);

与:

class SomeCompilerGeneratedType {
    public Foo obj;
    public void SomeCompilerGeneratedMethod() {
        Console.WriteLine(obj.name); 
    }
}

关于C# 闭包变量作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32580033/

相关文章:

c# - 设计器编辑 UserControl 中 DataGridView 的 DataSource 属性

c# - 当 null 条件运算符短路时,它是否仍然评估方法参数?

c# - ASP Core 无法在 VS 2017 中设置用户 secret

c# - 在 VS 2010 中为测试项目设置 useLegacyV2RuntimeActivationPolicy

c# - 在 C# 中使用反射识别自定义索引器

.net - Windbg 中的 WaitForMultipleObjects 是否表明 .NET 应用程序中的事件存在问题?

c# - 建立一个简单的 websocket 握手

c# - 如何让工具提示跟随鼠标?

C# 拖放在 Windows 7 上不起作用

.net - Azure 启动任务挂起