我将一个 Action 存储在局部变量中,然后在该局部变量超出范围后使用。在我使用它之前是否有被清理的危险?这是一个例子:
public List<object> GetMaps() {
Action<Customer1, Customer2> baseMap = (Customer1 c1, Customer2 c2) => {
c2.FirstName = c1.FirstName;
};
var list = new List<object>() {
new Action<SpecialCustomer1 c1, SpecialCustomer2 c2>() {
baseMap(c1, c2);
c2.SpecialProperty = c1.SpecialProperty;
},
new Action<SpecialCustomer1 c1, SpecialCustomer2 c2>() {
baseMap(c1, c2);
c2.SpecialProperty2 = c1.SpecialProperty2;
},
};
return list;
}
因此,您可以在此示例中看到该函数正在返回调用 baseMap
的操作列表。 baseMap
只是一个局部变量。它在其他操作中被调用这一事实足以让 .NET 知道不要清理它吗?
最佳答案
我建议您参阅 C# 4 规范的第 5.1.7 节,其中说:
If the local variable is captured by an anonymous function, its lifetime extends at least until the delegate or expression tree created from the anonymous function, along with any other objects that come to reference the captured variable, are eligible for garbage collection.
即使控制通过了本地范围的末尾,本地的生命周期也会延长。在实践中,我们通过将局部变量转换为闭包类的字段,然后通过在委托(delegate)(或表达式树)中引用它来保持类的事件来实现这一点。
请注意,您可能会遇到相反的问题;有时事物的生命周期比您希望的要长:
Expensive expensive = new Expensive();
Cheap cheap = new Cheap();
Action longlived = ()=>M(cheap);
Action shortlived = ()=>M(expensive);
今天在 C# 中的工作方式是为两个委托(delegate)生成的闭包使“廉价”和“昂贵”的事件与长生命周期委托(delegate)的生命周期保持一致,即使长生命周期委托(delegate)实际上并不存在用“贵”! (VB、JScript 等很多有闭包的语言也有这个问题。)
我们在这里可以做的是在编译器中检测这种情况并创建两个闭包。我们正在考虑为 C# 的 future 版本这样做。
关于c# - Action/Lambda 表达式内存管理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6202988/