如何在C#中正确释放匿名委托/闭包?

时间:2011-02-24 09:41:03

标签: c# lambda delegates closures

我正在开发一个GUI应用程序,它严重依赖Action<>个委托来自定义UI工具的行为。我想知道我们这样做的方式是否有任何潜在的问题,例如实现是否保留对捕获的变量的引用,声明委托的类实例等?

所以我们假设我们有这个类MapControl,它包含一个有状态的GUI控件。地图有不同种类的工具(绘图,选择等),由ITool界面表示。您可以使用StartTool()设置工具,但一次只能激活一个工具,因此当设置另一个工具时,前一个工具将使用StopTool()停止。当工具停止时,将执行调用者指定的回调委托。

public class MapControl
{
    ITool _currentTool;
    Action<IResult> _onComplete;

    public void StartTool(ToolEnum tool, Action<IResult> onComplete) {

        //If tool is active, stop it first
        if (_currentTool != null) StopTool();

        _onComplete = onComplete;

        //Creates a tool class, etc.
        _currentTool = CreateTool(tool) as ITool;
    }

    public void StopTool() {

        //Execute callback delegate
        IResult result = _currentTool.GetResult();
        if (_onComplete != null)
            _onComplete(result);

        //Nix the references to callback and tool
        _onComplete = null;
        _currentTool = null;
    }
}

在应用程序的ViewModel类中,我们设置了一些这样的工具:

class ViewModel
{
    private MapControl _mapControl = new MapControl();
    public void SetSomeTool() 
    {
        //These variables will be captured in the closure
        var someClassResource = this.SomeClassResource;
        var someLocalResource = new object();

        //Start tool, specify callback delegate as lambda
        _mapControl.StartTool(ToolEnum.SelectTool, (IResult result) => {

            //Do something with result and the captured variables
            someClassResource.DoSomething(result, someLocalResource);
        });
    }
}

在我们的例子中,ViewModel类附加到WPF应用程序的主窗口,并且在应用程序生命周期中只能有一个ViewModel实例。如果不是这样的话,它会改变什么吗?声明代表的类会更短暂吗?

我的问题是,我是否正确处理了回调委托?是否有任何情况,这可能会导致内存膨胀,因为它不应该继续引用它?

更一般地说,处理匿名代表的安全和正确方法是什么?

4 个答案:

答案 0 :(得分:2)

恕我直言,没关系,你没有坚持任何你不需要的参考资料。清除StopTool中的引用后,您将不再持有它们。

答案 1 :(得分:2)

你可以通过这种方式删除方法参考。


你问的还有一件事:

  

我的问题是,我是否正确处理了回调委托?

你没有处理方法(或指向方法的指针),只有类。

答案 2 :(得分:0)

我认为更合适的方式是:

_onComplete = (Action<IResult>)Delegate.Remove(null, _onComplete);

答案 3 :(得分:0)

如果您想确保正确处理所有未使用的对象,我建议您使用CLR Profiler之类的工具,这样您就可以全面了解应用程序如何分配/释放内存。