One Liner: WeakReference-to-a-Lambda Event Handler - c#

Can you see downsides to this one-liner other than the fact that multiple uses of it would violate the DRY principle? It seems straightforward but the fact that I haven't seen others propose it makes me wonder if there's a downside to it.
This bit of code creates a WeakReference to a method and then registers an event handler that invokes the reference's target.
SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)();
Thanks,
Ben

I don't think that pattern does what you expect. Are you trying to prevent the event from holding a reference to the current object so as to prevent memory leaks? The lambda expression will capture the value of this in order to evaluate ProcessEvent (assuming ProcessEvent is an instance method), so you will still have the leak. This code is the same as doing SomeEvent += (sender, e) => ProcessEvent();.
You may be trying to do something more like this (which also isn't what you want):
var reference = new WeakReference((Action)ProcessEvent);
SomeEvent += (sender, e) => ((Action)reference.Target)();
Now the lambda expression will capture the WeakReference, so you won't have a strong reference to this. Unfortunately, nothing else is referencing the delegate created from ProcessEvent, so it will be removed on the next GC even if this is still alive. (This also doesn't check for Target being null).
You could try something like this:
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;
}
and then use it like this:
SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h);
That will keep a weak reference to the receiver of ProcessEvent, and will automatically remove the event handler from the event after it has been collected, which should prevent memory leaks as long as the event is raised regularly.

Its not very readable. And if you have to debug it by stepping through, any one of those actions could fail, but that single line would fail. Also, you'd only get that single line referenced in a stack trace.
You generally want to avoid doing too many things in a single line for maintainability.

Related

Do i have to unsubscribe from anonymous event handlers of local variables?

If I have a code that looks something like this:
public void Foo()
{
Bar bar = new Bar();
bar.SomeEvent += (sender, e) =>
{
//Do something here
};
bar.DoSomeOtherThingAndRaiseSomeEvent();
}
Will bar be collected when the method runs out of the scope, or will I have to manually unsubscribe from the event to prevent a memory leak because of a reference to SomeEvent?
Your situation is fine; the event subscriber will not prevent the publisher from being collected, but the opposite can happen.
For example,
class Foo
{
public event EventHandler FooEvent;
void LeakMemory()
{
Bar bar = new Bar();
bar.AttachEvent(this);
}
}
class Bar
{
void AttachEvent(Foo foo)
{
foo.FooEvent += (sender, e) => { };
}
}
In this case, the instance of Bar created within LeakMemory can't be collected until either
The anonymous method represented by the lambda is removed from FooEvent's invocation list
The instance of Foo to which it's attached can be collected
This is because the event (which is just some syntactic sugar over an ordinary delegate instance) holds onto a list of delegates to invoke when it's invoked, and each of these delegates has, in turn, a reference to the object that it's attached to (in this case, the instance of Bar).
Note that we're only talking about collection eligibility here. Just because it's eligible doesn't say anything about when (or even, really, if) it will be collected, just that it can be.
Well, the object bar refers won't be automatically garbage collected immediately... it's just that the bar variable won't prevent it from being garbage collected.
The event handler won't prevent the instance of Bar from being garbage collected either though - the "normal" problem is that an event handler keeps the subscriber of an event from being garbage collected (if it uses an instance method or captures "this" in an anonymous function). It doesn't usually affect the publisher being garbage collected. Just remember that the publisher needs to keep a reference to all the subscribers - the subscriber doesn't need to remember what it's subscribed to, unless it explicitly wants to unsubscribe or use some other member later.
Assuming nothing else is keeping your instance of Bar alive, your code should be fine.
The above answers are correct; I just wanted to make a note. Anonymous delegates used as handlers can only be unsubscribed if you retain some other reference to the delegate/lambda. This is because lambdas are "function literals", kind of like string literals, however unlike strings they are NOT compared semantically when determining equality:
public event EventHandler MyEvent;
...
//adds a reference to this named method in the context of the current instance
MyEvent += Foo;
//Adds a reference to this anonymous function literal to MyEvent
MyEvent += (s,e) => Bar();
...
//The named method of the current instance will be the same reference
//as the named method.
MyEvent -= Foo;
//HOWEVER, even though this lambda is semantically equal to the anonymous handler,
//it is a different function literal and therefore a different reference,
//which will not match the anonymous handler.
MyEvent -= (s,e) => Bar();
var hasNoHandlers = MyEvent == null; //false
//To successfully unsubscribe a lambda, you have to keep a reference handy:
EventHandler myHandler = (s,e) => Bar();
MyEvent += myHandler;
...
//the variable holds the same reference we added to the event earlier,
//so THIS call will remove the handler.
MyEvent -= myHandler;

Does an event need to have at least one handler?

Why event needs to have at least one handler?
I created custom event for my Control and somewhere inside of code of my control, I call this event:
this.MyCustomEvent(this, someArgs);
it throws a NullReferenceException if there is no handler subscribed to it.
When I added a single handler in control's constructor, everything works fine:
this.MyCustomEvent += myCutomEventHandler;
void myCustomEventHandler(object sender, EventArgs e)
{ /* do nothing */ }
Is this normal or maybe I'm doing something wrong?
Shouldn't it check automatically if there are any handlers subscribed? It's a little dumb, IMHO.
I recommend you to have an extremely useful extension method:
public static void Raise<T>(this EventHandler<T> eventHandler, object sender, T e) where T : EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, e);
}
}
which will do the check for you.
Usage:
MyCustomEvent.Raise(this, EventArgs.Empty);
Note that delegates are reference types, and their default value is null.
The solution proposed by others, i.e. to check for null before firing the event, is not thread-safe because listeners may unsubscribe from the event between the null check and the firing of the event.
I have seen solutions that involve copying the delegate to a local variable, and checking it for null before firing, such as
EventHandler myCustomEventCopy = MyCustomEvent;
if (myCustomEventCopy != null)
{
myCustomEventCopy (this, someArgs);
}
But this has a race-condition, i.e. handlers may fire even after they have unsubscribed from the event, which may corrupt the state of the application.
One solution that handles both problems is to initialize events to a blank handler, e.g.
public event EventHandler MyCustomEvent = delegate { };
and then fire them off without any checks, e.g.
MyCustomEvent(this, someArgs);
Edit: As others have pointed out, this is a complex issue.
http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx
Lippert points out that completely removing the "handler is fired after deregistration" problem requires that the handlers themselves are written in a robust manner.
An event at the bottom is MulticastDelegate, which is null if there is no method in the invocation list. Usually, you use a RaiseEvent() method to call an event, the pattern looks like the following:
public void RaiseEvent()
{
var handler = MyEvent;
if(handler != null)
handler(this, new EventArgs());
}
As you assign the event to a variable, it is threadsafe. You can miss a removed or added method though, which was added between the atomic operations (assignment -> null check -> invocation).
This is normal behaviour. The conventional pattern for throwing an event in .NET is to have a method called OnMyCustomEvent that you use to throw the event, like so:
protected void OnMyCustomEvent(MyCustomEventArgs e)
{
EventHandler<MyCustomEventArgs> threadSafeCopy = MyCustomEvent;
if (threadSafeCopy != null)
threadSafeCopy(this, e);
}
public event EventHandler<MyCustomEventArgs> MyCustomEvent;
Then from your code, you would call this.OnMyCustomEvent(someArgs) instead.
This is the normal behavior. To avoid this always test if there's an event subscriber before calling it:
if (MyCustomEvent != null)
{
MyCustomEvent(this, someArgs);
}
There is the "standard" approach of copying the reference and then checking for null (the value of the reference if no handlers are attached)—as given by other answers:
public EventHandler<MyEventArgs> MyEvent;
protected virtual OnMyEvent(MyEventArgs args) {
var copy = MyEvent;
if (copy != null) {
copy(this, args);
}
}
This works because, in part, MulticastDelegate instances are immutable.
There is another approach: the Null Object Pattern:
public EventHandler<MyEventArgs> MyEvent;
// In constructor:
MyEvent += (s,e) => {}; // No op, so it is always initialised
And there is no need to take a copy or check for null because it won't be. This works because there is no Clear method on an event.
Yes, you need to check for null. In fact, there's a right way to do it:
var myEvent = MyCustomEvent;
if (myEvent != null)
myEvent(this, someArgs);
This is the official right way because it avoids a possible race condition when the event is changed after the null check but before the call.

lambda expressions in C#?

I'm rather new to these could someone explain the significance (of the following code) or perhaps give a link to some useful information on lambda expressions? I encounter the following code in a test and I am wondering why someone would do this:
foo.MyEvent += (o, e) => { fCount++; Console.WriteLine(fCount); };
foo.MyEvent -= (o, e) => { fCount++; Console.WriteLine(fCount); };
My instinct tells me it is something simple and not a mistake, but I don't know enough about these expressions to understand why this is being done.
The lambda expression (o, e) => { fCount++; Console.WriteLine(fCount); } is interpreted as an anonymous method that takes two arguments o, e (whose types are inferred from the delegate type used for MyEvent and returns void. It captures the fCount variable in the body of the enclosing method (if it's a local variable). The += operator will subscribe the anonymous method to the event and the -= unsubscribes a delegate from an event.
Update (re: concerns about delegate instance equality):
It's important to know that it's not a good idea to try to unsubscribe from the event like that. The language specification, permits, but doesn't require that the delegate in the second line to be equal to the delegate from the first line. That is, the compiler is allowed to treat the two anonymous function bodies as if it was the same function or if it wasn't (because the anonymous function body is semantically identical and the set of captured variables is equal too). Even if it works as expected in your compiler, it might break in the next version. To quote the C# Language Specification on that:
C# Language Specification (Section 7.9.8 Delegate equality operators):
Invocation list entries produced from evaluation of semantically identical anonymous-function-expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.
If the compiler treats the two anonymous function expressions as equal, the second line will unsubscribe the previous anonymous method from the event. If it doesn't the second line will not do anything special (it's not an error to unsubscribe a delegate from an event invocation list if it doesn't already exist in the list).
Here is a great video about lambda expressions in C#. The video is 2 years old, but it gets users up to speed on the functionality that was relatively new at that time. The content you're interested begins around 3:02.
It is a mistake. It's adding an anonymous delegate to the MyEvent event, but trying to remove a different instance of the same anonymous delegate. Since the instance is probably always different, it may never actually remove the original delegate, which is almost certainly not what you want.
It is an implementation of an event handler using a lambda expression. The advantag is that it is a) inline, i.e. no additional function declaration is required and b) that it can draw on the variables declared in the function where you found this declaration (using closures).
It looks like he's thinking that's equivalent to:
var eh = new EventHandler(delegate(object o, EventArgs e)
{ fCount++; Console.WriteLine(fCount); };
foo.MyEvent += eh;
foo.MyEvent -= eh;
But the unregistering isn't going to work as expected since it has no way of knowing its supposed to be referring to the registered delegate.
The syntax he's using for adding the handler is just a shorter way of attaching an anonymous delegate to an event and is pretty popular syntax, but not something I'd recommend using if you also have to unregister it.
Lambda expressions are a syntactic shorthand to declare a function. So,
(o, e) => { fCount++; Console.WriteLine(fCount); }
means a function that takes two arguments and executes two statements.
As for the code snippet, the unsubscribe '-=' will not work because it is shorthand for:
foo.MyEvent += new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent -= new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
This is actually a resource leak. Instead store a reference to the handler and use that to perform the subscribe and unsubscribe:
var handler = new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent += handler;
foo.MyEvent -= handler;

C# Delegates and Events design help

I have some code in my project that saves an object to the database, once this is done I want it to call a series of other methods.
I was thinking about allowing other methods to subscribe to this event so I can add more as I need to. The idea I had for this was to create an array of Delegates allowing other methods to register, then when the object had been saved it could loop through the delegates and call each one.
Would this be bad practise or is there a better way of doing this?
Thanks
Event delegates are multicast, which means that they can hold references to more than one event handling method - see the MSDN documentation for Delegate and MulticastDelegate.
The syntax for subscribing to an event gives a clue:
MyEvent += MyHandler; // subscribe to an event
MyEvent -= MyHandler; // unsubscribe from an event
You can subscribe as many delegates as you want to a single event. Under the hood .Net keeps these as an ordered collection anyway.
The standard pattern for this is:
//in your class
public EventHandler<MyEvtArgs> MyEvent;
protected void OnMyEvent ( MyEvtArgs args ) {
if(MyEvent != null) //make sure there is at least 1 subscriber
MyEvent(this, args);
}
Then to call this:
var myInstance = new MyClass();
// all of these can convert to EventHandler<MyEvtArgs> (object, MyEvtArgs)
myInstance.MyEvent += (sender, e) => { /* do something 1 */ };
myInstance.MyEvent += (sender, e) => { /* do something 2 */ };
myInstance.MyEvent += localMethod;
Now when your protected OnMyEvent method is called inside your class all of these events will fire - in order.
You can also remove items from this collection:
myInstance.MyEvent -= localMethod;
You don't need an array. Just let anyone subscribe to one.
You can use a normal event for this. The runtime will handle looping over all fields.
public event EventHandler<EventArgs> WritingToDatabaseFinished;
protected void OnWritingToDatabaseFinished(EventArgs args)
{
EventHandler<EvetnArgs> handler = WritingToDatabaseFinished;
if (handler != null)
{
handler(this, args);
}
}
Your code calls
OnWritingToDatabaseFinished(args);
All methods that want to be informed have to register to the event:
WritingToDatabaseFinished += new EventHandler<EventArgs>(handlermethod);
Every handler that has been registered in the above way will be called when you call OnWritingToDatabaseFinished.
All you need is a multicast delegate. You don't need an array at all. You use += to add a reference to the delegate, and a -= to remove the reference.
I would recommend that you look at using a weak event handler instead. Take a look at this link to see why you'd use a weak event instead of a weak delegate.
Delegates are already multicast, so no need for a delegate array. Now, the recommended way of adding event support to your class is:
Add a public delegate (this will be your event handler)
public delegate void DatabaseEventHandler(object sender, DatabaseEventArgs e);
Add a public event, of your delegate type.
public event DatabaseEventHandler DatabaseDone;
Now, the event should send 2 parameters. The sender (this, usually), and the EventArgs. You should create a new class from System.EventArgs, and send the appropriate information within that class.

C# - anonymous functions and event handlers

I have the following code:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
Notice how I register my event member (FoundStep) to local in-place anonymous function.
My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)
I hope my question was clear.
Your code has a few problems (some you and others have identified):
The anonymous delegate cannot be removed from the event as coded.
The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.
To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
Below is approach about how unsubscribe event in anonymous method:
DispatcherTimer _timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
EventHandler handler = null;
int i = 0;
_timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev)
{
i++;
if(i==10)
_timer.Tick -= handler;
});
_timer.Start();
No, it will not be removed automatically. In this sense, there's not a difference between an anonymous method and a "normal" method. If you want, you should manually unsubscribe from the event.
Actually, it'll capture other variables (e.g. res in your example) and keep them alive (prevents garbage collector from collecting them) too.
When using an anonymous delegate (or a lambda expression) to subscribe to an event does not allow you to easily unsubscribe from that event later. An event handler is never automatically unsubscribed.
If you look at your code, even though you declare and subscribe to the event in a function, the event you are subscribing to is on the class, so once subscribed it will always be subscribed even after the function exits. The other important thing to realize is that each time this function is called, it will subscribe to the event again. This is perfectly legal since events are essentially multicast delegates and allow multiple subscribers. (This may or may not be what you intend.)
In order to unsubscribe from the delegate before you exit the function, you would need to store the anonymous delegate in a delegate variable and add the delegate to the event. You should then be able to remove the delegate from the event before the function exits.
For these reasons, if you will have to unsubscribe from the event at some later point it is not recommended to use anonymous delegates. See How to: Subscribe to and Unsubscribe from Events (C# Programming Guide) (specifically the section titled "To subscribe to events by using an anonymous method").

Categories

Resources