Один вкладыш: WeakReference-to-a-Lambda обработчик событий - PullRequest
9 голосов
/ 16 июля 2010

Можете ли вы увидеть недостатки этого однострочника, кроме того факта, что его многократное использование нарушит принцип DRY ? Это кажется простым, но тот факт, что я не видел, как другие предлагают, заставляет задуматься, есть ли в этом недостаток.

Этот бит кода создает WeakReference для метода, а затем регистрирует обработчик события, который вызывает цель ссылки.

SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)();

Спасибо
Бен

Ответы [ 2 ]

12 голосов
/ 16 июля 2010

Я не думаю, что этот шаблон делает то, что вы ожидаете. Вы пытаетесь предотвратить удержание события ссылки на текущий объект, чтобы предотвратить утечки памяти? Лямбда-выражение будет фиксировать значение this, чтобы оценить ProcessEvent (при условии, что ProcessEvent - это метод экземпляра), поэтому утечка все равно останется Этот код такой же, как и для SomeEvent += (sender, e) => ProcessEvent();.

Возможно, вы пытаетесь сделать что-то более похожее на это (что тоже не то, что вы хотите):

var reference = new WeakReference((Action)ProcessEvent);
SomeEvent += (sender, e) => ((Action)reference.Target)();

Теперь лямбда-выражение будет захватывать WeakReference, поэтому у вас не будет сильной ссылки на this. К сожалению, ничто иное не ссылается на делегат, созданный из ProcessEvent, поэтому он будет удален на следующем GC, даже если this еще жив. (Это также не проверяет, является ли цель недействительной).

Вы можете попробовать что-то вроде этого:

public EventHandler MakeWeakHandler(Action action, Action<EventHandler> remove)
{
    var reference = new WeakReference(action.Target);
    var method = action.Method;
    EventHandler handler = null;
    handler = delegate(object sender, EventArgs e)
    {
        var target = reference.Target;
        if (target != null)
        {
            method.Invoke(target, null);
        }
        else
        {
            remove(handler);
        }
    };
    return handler;
}

, а затем используйте его так:

SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h);

Это сохранит слабую ссылку на получатель ProcessEvent и автоматически удалит обработчик события из события после его сбора, что должно предотвратить утечки памяти, если событие вызывается регулярно.

0 голосов
/ 16 июля 2010

Это не очень читабельно. И если вам придется отлаживать его, выполняя пошаговое выполнение, любое из этих действий может потерпеть неудачу, но эта единственная строка потерпит неудачу. Кроме того, в трассировке стека указывается только одна строка.

Как правило, вы хотите избежать слишком большого количества операций в одной строке для удобства обслуживания.

...