Search code examples
c#eventsweak-references

WeakReference too weak?


I've implemented this WeakEvent Delegate but for some reason it only works for a few seconds, and after that it stops working:

public class WeakEventHandler<TE>  where TE : EventArgs
{
    private readonly Action<WeakEventHandler<TE>> _unsubscriber;
    private readonly WeakReference<EventHandler<TE>> _targetRef;
    private readonly EventHandler<TE> _handler;


    public WeakEventHandler(EventHandler<TE> eventReceiver, Action<WeakEventHandler<TE>> unsubscriber)
    {
        _unsubscriber = unsubscriber;
        _targetRef = new WeakReference<EventHandler<TE>>(eventReceiver);
        _handler = Invoke;
    }

    public void Invoke(object sender, TE e)
    {
        EventHandler<TE> method;

        if (_targetRef.TryGetTarget(out method))
        {
            method(sender, e);
        }
        else
        {
            _unsubscriber(this);
        }

    }

    public static implicit operator EventHandler<TE>(WeakEventHandler<TE> weh)
    {
        return weh._handler;
    }
}

public static class EventHandlerUtils
{
    public static EventHandler<TE> MakeWeak<TE>(this EventHandler<TE> eventReceiver, Action<WeakEventHandler<TE>> unsubscriber) where TE : EventArgs
    {
        return new WeakEventHandler<TE>(eventReceiver, unsubscriber);
    }
}

Usage:

    private EventHandler<MouseInteractionArgs> _mouseInteractionDelegate;

    public event EventHandler<MouseInteractionArgs> MouseAction
    {
        add
        {
            _mouseInteractionDelegate += value.MakeWeak(handler => _mouseInteractionDelegate -= handler );
        }

        remove
        {
            throw new InvalidOperationException("This is a weak Event, dont worry about unsubscribing");
        }
    }

I never stop referencing the owner of the method, so I dont know why it is not working, do delegates behave different?


Solution

  • but the "eventreceiver" is owned by the instance of the method

    Sorry, but you have that backwards. The "eventReceiver" is the delegate instance that you are adding to the MouseAction event. That delegate instance retains a reference to the target object and MethodInfo, not the other way around. There's no code retaining the reference to the delegate instance except your WeakReference and of course by design that's not enough to keep the object alive.