Unsubscribe Anonymous Method in C#

Unsubscribe anonymous method in C#


Action myDelegate = delegate(){Console.WriteLine("I did it!");};

MyEvent += myDelegate;


// .... later

MyEvent -= myDelegate;

Just keep a reference to the delegate around.

Unsubscribing from anonymous delegate event

Anonymous delegates are not guaranteed to be unique as created by the compiler, when unsubscribing this lack of uniqueness of the same code will cause it to fail to unsubscribe the correct handler. The only way to do so safely is to keep a reference to the delegate and use that to unsubscribe, or change it to a full method.

Delegates are equal based on object instance and method signature I believe.

A possible duplicate:

How to remove a lambda event handler

Basically, keep a reference:

MouseEventHandler handler = (sender, e) =>
{
Dragging = true;
DragStart = new Point(e.X, e.Y);
control.Capture = true;
};

control.MouseDown += handler;
control.MouseDown -= handler;

Or turn the anonymous method into a proper method.

Adding and Removing Anonymous Event Handler

There's an MSDN page that talks about this:

How to Subscribe to and Unsubscribe from Events

Note in particular:

If you will not have to unsubscribe to [sic]
an event later, you can use the
addition assignment operator (+=) to
attach an anonymous method to the
event.

And also:

It is important to notice that you
cannot easily unsubscribe from an
event if you used an anonymous
function to subscribe to it. To
unsubscribe in this scenario, it is
necessary to go back to the code where
you subscribe to the event, store the
anonymous method in a delegate
variable, and then add the delegate to
the event . In general, we recommend
that you do not use anonymous
functions to subscribe to events if
you will have to unsubscribe from
the event at some later point in your
code.


Can an anonymous delegate unsubscribe itself from an event once it has been fired?

You can save an instance of the delegate before subscribing to the event:

public void QueueNotAvailable() 
{
SomeHandler handler = null;
handler = (s,e) {
// ...
StateChanged -= handler;
};
StateChanged += handler;
}

I believe this should do it... I had to put the initial handler = null in there otherwise you get 'Use of unassigned local variable' compilation errors, but I think it's actually benign.

How to unsubscribe an anonymous function in Dispose method of a class?

You can't, basically. Either move it into a method, or use a member variable to keep the delegate for later:

public class A : IDisposable
{
private readonly EventHandler handler;

public A()
{
handler = (sender, e) =>
{
Line 1
Line 2
Line 3
Line 4
};

B_Object.DataLoaded += handler;
}

public override void Dispose()
{
B_Object.DataLoaded -= handler;
}
}

Event unsubscription via anonymous delegate

You can extract the lamdba to a variable:

EventHandler func = (sender, e) =>
listView_PreviewTextInput(sender, e, listView);

if (((bool)e.NewValue))
{
listView.PreviewTextInput += func;
}
else
{
listView.PreviewTextInput -= func;
}

Unsubscribe events vis anonymous delegate

New answer, now the question has changed

You can't, basically. Your handler depends on dependencyObject, which will be captured in a new object on each call, so you'll end up with unequal delegates.

You could create a new class which holds the dependency object and overrides Equals to compare those objects instead of using anonymous functions, or you could just hold a reference to the previously-subscribed handler.


Old answer, when the delegate didn't depend on the parameters

The bizarre thing is that in this particular case, it looks like you're not capturing any local variables. So it's possible that if the only place you're subscribing to the event is from this method, you could get away with:

private static void Test(Object a, DependencyPropertyChangedEventArgs args)
{
NotifyCollectionChangedEventHandler handler =
(s, e) => SelectedItemsChanged(dependencyObject, e);

var oldObservable = args.OldValue as ObservableCollection<object>;
if (oldObservable != null)
{
oldObservable.CollectionChanged -= handler;
}
var newObservable = args.NewValue as ObservableCollection<object>;
if (newObservable != null)
{
newObservable.CollectionChanged += handler;
}
}

As you've only got one lambda expression now, I'd expect that to be converted into a single static method, so the freshly-created delegate will be equal to the original one.

However, I wouldn't recommend that. I'd just create the method yourself, and then use a method group conversion.

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

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.

How do I Unregister 'anonymous' event handler

If you need to unregister an event, I recommend avoiding anonymous delegates for the event handler.

This is one case where assigning this to a local method is better - you can unsubscribe from the event cleanly.

Removing anonymous event handler

You can refer to your anonymous method from inside itself as long as you assign a delegate to a variable first:

EventHandler<SomeEventArgs> handler = null;
handler = (s, e) =>
{
_client.AddMemberToTeamCompleted -= handler;
callback(e.Result);
};

_client.AddMemberToTeamCompleted += handler;

Note that you need to declare the variable and assign it separately or the compiler will deem it uninitialized when you come to use it inside the method body.



Related Topics



Leave a reply



Submit