上代码
internal class Program
{
static void Main(string[] args)
{
Func1();
GC.Collect();
Console.WriteLine("End");
Console.ReadLine();
}
static void Func1()
{
A a = new A();
a.Callback((str)=>Console.WriteLine(str));
}
static void Callback(Action<string> success)
{
Task.Run(() => {
Task.Delay(10 * 500).Wait();
success("Ok");//为啥能正常运行,是因为闭包延长了success的作用域么?
});
}
}
class A
{
public void Func1()
{
Callback((str) => Console.WriteLine(str));
}
public void Callback(Action<string> success)
{
Task.Run(() => {
Task.Delay(10 * 500).Wait();
success.Invoke("Ok");//为啥能正常运行,是因为闭包延长了success的作用域么?
});
}
}
是的。success
能够在 Task
中正常执行,这是因为它被闭包(Closures)捕获了。
在 C# 中,当你在一个方法内部创建一个委托时,并且这个委托引用了该方法的局部变量,那么就会形成一个闭包。闭包可以保留对这些局部变量的引用,即使这些方法已经返回并且其局部作用域已经不存在了。
在你的代码中,Action<string> success
是一个委托,它在 Func1
或者 Callback
方法的作用域中被定义,然后被传给另一个任务去执行。这个任务在其他线程上异步运行,可能在 Func1
或 Callback
方法已经返回之后。由于闭包,这个任务依然能访问 success
并成功调用它。
至于“提升到哪里了”,闭包是将局部变量 "提升" 到了包含这个方法的类的实例级别。所以,只要这个实例还存在,这个变量就可以被访问,不论原始的作用域是否还存在。这有助于理解为什么 GC.Collect()
不会回收这个变量,因为它仍然被包含它的对象引用(即使原来的方法已经返回)。