关于闭包如何应用变量范围的(另一个?)问题。这是一个最小的例子:
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
的闭包。 obj
与 obj1
具有相同的引用 value 但它与 obj1
的关系到此为止,因为闭包仅包含 对象
。换句话说,obj1
之后取的任何值都不会影响闭包。因此无论何时/无论如何 a
被调用(例如 a
被传递给其他一些函数)它总是打印 x1
。
现在我的问题是:
- 以上解释是否正确?
- 我没有想到具体的场景,但如果我们希望程序打印
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/