Мысли
Мне нравится идея реализации слабого делегата на стороне класса, который обрабатывает событие, потому что я не хочу иметь слабые ссылки только в некоторых случаях. Для моей личной структуры пользовательского интерфейса я иногда реагирую на события, не имея ссылки на исходный объект:
void HandlePropertyChanged(Object sender, PropertyChangedArgs args)
{
// Do some stuff with the sender
}
Для этого требуются неслабые делегаты, в то время как для других объектов требуются слабые.
Решение
Я наткнулся на те же проблемы, что и вы, и решил их, не используя WeakReference
для делегата, а используя WeakReference
для цели делегата и копируя пустой делегат.
// Create a weak reference to the target
_Sender = new WeakReference(target.Target);
_CallDelegate = (Action<TThis, TSender, TArgs>)Delegate.CreateDelegate(CallDelegateType, target.Method);
Это прекрасно работает, но осталась одна большая проблема: Как удалить событие, когда оно больше не используется?
Ну, для этого тоже есть решение, но решение требует некоторого кода отражения и является источником ошибок:
_RemoveMethod = (Action<DataEventHandler<TSender, TArgs>>)Delegate.CreateDelegate(AddMethodType, eventHolder, eventDeclaration.GetRemoveMethod());
eventDeclaration
является экземпляром EventInfo
и поставляется с аргументами конструктора, чтобы сделать его немного проще для пользователя. Я создал второй конструктор, который просто принимает экземпляр (eventHolder
) и строку, которая представляет название события.
Когда объект больше не жив, вызывается _RemoveMethod
-делегат, который удаляет WeakDelegate
.
Использование
n.Disposing += (_DisposeDelegate = new WeakDelegate<Drawable, IComponent,Object>(n, "Disposing", HandleRootDisposing));
Как вы можете видеть, есть еще одна проблема: WeakDelegate
должен храниться в памяти, когда требуется удалить событие позже. Для этого тоже есть решение, но оно требует переопределения методов равенства WeakDelegate
и сохранения всех делегатов в хеш-таблице, что может сильно замедлить работу приложения.