Один лайнер: обработчик событий WeakReference-to-a-Lambda

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

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

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

Спасибо,
Ben

9
задан Ben Gribaudo 15 July 2010 в 10:24
поделиться

2 ответа

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

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

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

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

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

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 и автоматически удалит обработчик события из события после его сбора, что должно предотвратить утечку памяти при условии, что событие поднимается регулярно.

12
ответ дан 2 November 2019 в 23:58
поделиться

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

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

0
ответ дан 2 November 2019 в 23:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: