OK, so this is more of an answer than a question, but after asking this question, and pulling together the various bits from Dustin Campbell, Egor, and also one last tip from the 'IObservable/Rx/Reactive framework', I think I've worked out a workable solution for this particular problem. It may be completely superseded by IObservable/Rx/Reactive framework, but only experience will show that.
I've deliberately created a new question, to give me space to explain how I got to this solution, as it may not be immediately obvious.
There are many related questions, most telling you you can't use inline lambdas if you want to be able to detach them later:
- Weak events in .Net?
- Unhooking events with lambdas in C#
- Can using lambdas as event handlers cause a memory leak?
- How to unsubscribe from an event which uses a lambda expression?
- Unsubscribe anonymous method in C#
And it is true that if YOU want to be able to detach them later, you need to keep a reference to your lambda. However, if you just want the event handler to detach itself when your subscriber falls out of scope, this answer is for you.
If you head over to CodePlex there's a project called Sharp Observation in which the author has built a good weak delegate provider, implemented in MSIL. Fast, flexible, easy to use: e.g.
As easy as that!
'The' answer
(Read more below if you want to see how I got to this solution)
Usage, given a control with a vanilla
MouseDown
event, and a specificEventHandler<ValueEventArgs> ValueEvent
event:(*This is a workaround from Rx)
(** it is important to avoid invoking the subscriber object directly here (for instance putting subscriber.DoSomething(e), or invoking DoSomething(e) directly if we are inside the Subscriber class. Doing this effectively creates a reference to subscriber, which completely defeats the object...)
Note: in some circumstances, this CAN leave references to the wrapping classes created for the lambdas in memory, but they only weigh bytes, so I'm not too bothered.
Implementation:
The detail
My starting point was Egor's excellent answer (see link for version with comments):
What bothered me was that the event is hard coded into the method. So that means for each new event, there is a new method to write.
I fiddled around and managed to come up with this generic solution:
However the problem with that solution is that it is ONLY generic, it can't handle the standard winforms MouseUp, MouseDown, etc...
So I tried to make it even more generic:
However, as I hinted here, this won't compile, because there is no way of constraining T to be a delegate.
At that point, I pretty much gave up. There's no point trying to fight with the C# specs.
However, yesterday, I discovered the Observable.FromEvent method from the Reactive framework, I didn't have the implementation, but the usage seemed slightly familiar, and very interesting:
It was the first argument that caught my attention. This is the workaround for the absence of a delegate type constraint. We take of it by passing in the function which will create the delegate.
Putting all this together gives us the solution shown at the top of this answer.
Afterthought
I thoroughly recommended taking the time to learn about the reactive framework (or whatever it ends up being called). It is VERY interesting, and slightly mindblowing. I suspect that it will also render questions like this totally redundant.
So far, the most interesting stuff I've seen has been the videos on Channel9.
I have been looking for a solution for a long time and most use nasty reflection but Benjohl's answer is great. I have tweaked it to add support for non-generic EventHandler, DependencyPropertyChangedEventArgs which does not inherit from EventArgs and to allow you to manually unregister an event yourself. I would be very interested in peoples thoughts, especially Benjohl.
Dustin Campbell's approach is already excellent. The only thing left, save a solution integrated into .NET, is a really simple way to create really generic weak event handlers:
http://puremsil.wordpress.com/2010/05/03/generic-weak-event-handlers/