c# – 动作/ Lambda表达式内存管理问题

我在一个局部变量中存储一个动作,然后我在该局部变量超出范围之后使用.在使用它之前是否有被清理的危险?这是一个例子:

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.

即使控制通过了本地范围的结束,也延长了本地的生命周期.在实践中,我们通过将local转换为闭包类的字段,然后通过在委托(或表达式树)中引用它来使类保持活动来实现此目的.

请注意,你可能遇到相反的问题;有时事情比你想要的更长寿:

Expensive expensive = new Expensive();
Cheap cheap = new Cheap();
Action longlived = ()=>M(cheap);
Action shortlived = ()=>M(expensive);

今天在C#中的工作方式是为两个代表生成的闭包只要长寿代表的生命周期保持“便宜”和“昂贵”,即使长寿代表实际上并不使用“昂贵” “! (VB,JScript和许多其他有闭包的语言也存在这个问题.)

我们在这里可以做的是在编译器中检测这种情况并创建两个闭包.我们正在考虑为未来版本的C#做这件事.

翻译自:https://stackoverflow.com/questions/6202988/action-lambda-expression-memory-management-question

转载注明原文:c# – 动作/ Lambda表达式内存管理问题