Как правильно освободить анонимных делегатов / замыканий в C #? - PullRequest
3 голосов
/ 24 февраля 2011

Я работаю над приложением с графическим интерфейсом, которое в значительной степени полагается на Action<> делегатов для настройки поведения наших инструментов пользовательского интерфейса.Мне интересно, есть ли потенциальные проблемы в том, как мы это делаем, например, сохраняет ли реализация ссылки на захваченные переменные, экземпляры классов, которые объявляют делегатов и т. Д.?

Итак, допустим, у нас есть класс MapControl, который обертывает элемент управления с графическим интерфейсом.Карта имеет различные виды инструментов (Рисование, Выбор и т. Д.), Представленные интерфейсом 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 ]

2 голосов
/ 24 февраля 2011

Вы справляетесь с удалением ссылки на методы таким образом.


Еще одна вещь, которую вы спросили:

Мой вопрос, я избавляюсь от обратного вызоваправильно делегаты?

Вы не располагаете методами (или указателями на методы в этом отношении), только классы.

2 голосов
/ 24 февраля 2011

ИМХО, это нормально, и вы не держитесь за ссылки, которые вам не нужны. С очисткой ссылок в StopTool вы больше не держите их.

0 голосов
/ 24 февраля 2011

Если вы хотите убедиться, что правильно утилизируете все неиспользуемые объекты, я бы посоветовал вам использовать такие инструменты, как CLR Profiler , чтобы вы могли иметь полное представление о том, как ваше приложение выделяет / освобождение памяти.

0 голосов
/ 24 февраля 2011

Я думаю, что более правильный путь будет:

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