UPDATE
I have combined various answers from here into a \'definitive\' answer on a new question.
Original question
Building further on Egor's answer, I wanted to try and build a version where I didn't have to determine in advance which event I want to attach to.
I've only managed to make it work with generic event handlers: for 'standard' event handlers (eg. FormClosingEventHandler), it's a bit tricky, because you can't have a type constraint where T : delegate (unless your name ends with Pony).
private static void SetAnyGenericHandler(
Action> add, //to add event listener to publisher
Action> remove, //to remove event listener from publisher
S subscriber, //ref to subscriber (to pass to consume)
Action consume) //called when event is raised*
where T : EventArgs
where S : class
{
var subscriber_weak_ref = new WeakReference(subscriber);
EventHandler handler = null;
handler = delegate(object sender, T e)
{
var subscriber_strong_ref = subscriber_weak_ref.Target as S;
if(subscriber_strong_ref != null)
{
Console.WriteLine("New event received by subscriber");
consume(subscriber_strong_ref, e);
}
else
{
remove(handler);
handler = null;
}
};
add(handler);
}
(*I did try EventHandler here, but the calling code gets ugly because you have to cast s to Subscriber in the consume lambda.)
Calling code example, taken from example above:
SetAnyGenericHandler(
h => publisher.EnabledChanged += h,
h => publisher.EnabledChanged -= h,
subscriber,
(Subscriber s, ValueEventArgs e) => s.Enabled = e.Value);
Or, if you prefer
SetAnyGenericHandler>(
h => publisher.EnabledChanged += h,
h => publisher.EnabledChanged -= h,
subscriber,
(s, e) => s.Enabled = e.Value);
It would be nice to be able to pass in the Event as just one parameter, but you can't access add/remove from an event any more than you can access get/set from a property (without doing yucky reflexion stuff, I think).