Detach event handler after attaching method with passed parameter - c#

I need to pass a parameter (in C#) to an event handler and then be able to detach the event handler.
I attach the event handler and pass the parameter:
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
The event is called as expected. I try to detach the event handler:
_map.MouseLeftButtonUp -= (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
The code executes without error, but does not seem to detach.
If I attach the event handler the more conventional way (without passing a parameter):
_map.MouseLeftButtonUp+=_map_MouseLeftButtonUp;
and detach
_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp;
everything works as expected
Detaching the event handler (that takes a parameter) via the more conventional way
_map.MouseLeftButtonUp -= _map_MouseLeftButtonUp2;
gives me an error saying the delegates don't match (which makes sense)
So my question is: Why is the event handler not really being detached when I pass a parameter, and is there a way to circumvent this problem.

When you create a lambda (anonymous) function, you're actually creating a new function each time.
The reason your first two lines don't work is because they are two completely different functions that just happen to do the same thing. The correct way to detach would be to have subscribe and unsubscribe from a function, as you've already figured out.
An alternative, that's probably not worth it, is to save your lambda to a variable.
Action<object, MouseButtonEventArgs> myEventMethod = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
_map.MouseLeftButtonUp += myEventMethod;
// ...
_map.MouseLeftButtonUp -= myEventMethod;

The reason is that two delegates are not equal:
// You add one delegate instance
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
// ..And try to remove another one (not previous!) That's why the first delegate remains unremoved
_map.MouseLeftButtonUp += (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
You can convince youself by
var x = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
var y = (sender, e) => _map_MouseLeftButtonUp2(sender, e, showResultsWindow);
if (Object.Equals(x, y)) { // <- You expected this behaviour
...
}
else { // <- Alas, this is a real situation: x != y
...
}
The reason of such a behaviour is that when Object.Equals is not overridden (and in case of delegates it's not) Object.Equals works as Object.RefrenceEquals does, which checks instances referenses (addresses). Sure, that addresses of x and y are different as well as two your delegates

Related

Observable.FromEvent signature

What is the purpose of having such a signature in Observable.FromEvent?
For example:
var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
In particular, what is h? And why +=, then -=? Do we make Observable from event or from event handler? If from event, why not just have a signature like:
var appActivated = Observable.FromEvent(Application.Current.Activated);
That's because there's no way to pass in an event as a parameter to a method. You could pass in the event as a delegate but that doesn't give you the ability to subscribe/unsubscribe to the event. See this answer by Eric Lippert.
Observable.From basically says "Ok, I will give you an observable that is a wrapper around the event, but you need to provide me with two delegates: 1) a delegate for me to subscribe my handler to the event, and 2) a delegate for me to unsubscribe my handler when I need to".
So in this case h => Application.Current.Activated += h is a lambda expression that gets compiled into a delegate. h (handler) is the input parameter, and the delegate takes that input parameter and subcribes it to the Activated event. And the second delegate is the same thing, except it unsubscribes the handler.
Eren's answer is correct; I want to make sure that all your questions are answered:
In particular, what is h?
h is a parameter to the delegates which add and remove handlers. When invoked, h will be a reference to a handler delegate.
And why +=, then -=?
The observable requires the ability to both subscribe and unsubscribe handlers to the event.
Do we make Observable from event or from event handler?
From an event.
If from event, why not just have a signature like: var appActivated = Observable.FromEvent(Application.Current.Activated); ?
Because that would pass the handler, not the event. An "event" is three things: the ability to invoke a handler list, the ability to add a new handler to the list, and the ability to remove a handler from the list. The observable needs the last two; your proposal is to pass the first. So the observable takes delegates which do the last two.
Observables are first-class types in .NET - meaning that you can keep a reference to them and pass them around as parameters to any constructor/method you like.
Events are not first-class types. They can only be attached and detached from in the scope that you can reference their containing object in.
So this means I cannot do this:
public void SomeMethod(EventHandler handler)
{
handler += (s, e) => { /* Handler Code */ };
}
public void SomeOtherMethod()
{
SomeMethod(Application.Current.Activated);
}
If I try that I get the error:
The event 'Application.Activated' can only appear on the left hand side of += or -=
That should let you know why you can't do var appActivated = Observable.FromEvent(Application.Current.Activated);.
So, how can I work around this to attach events in SomeMethod?
Here's how:
public void SomeMethod(Action<EventHandler> addHandler)
{
addHandler((s, e) => { /* Handler Code */ });
}
public void SomeOtherMethod()
{
SomeMethod(h => Application.Current.Activated += h);
}
Basically, in the method SomeMethod the parameter is no longer EventHandler, but Action<EventHandler>. This means I am no longer trying to pass the event itself - instead I'm passing a way for the called code to attach itself to my event. The h in the call to SomeMethod is a promise that in the future if I were to have a valid handler then I can attach it by invoking the Action<EventHandler>.
So let's say that I now want to write some code that knows how to attach and detach from an event. I now need this code:
public void SomeMethod(Action<EventHandler> addHandler, Action<EventHandler> removeHandler)
{
EventHandler handler = (s, e) => { /* Handler Code */ };
addHandler(handler);
/* Some Intervening Code */
removeHandler(handler);
}
public void SomeOtherMethod()
{
SomeMethod(h => Application.Current.Activated += h, h => Application.Current.Activated -= h);
}
In the /* Some Intervening Code */ code the handler is attached, and after it is detached.
This brings us to your code in your question:
var appActivated = Observable.FromEvent(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
This is very much the same as the SomeMethod call above - FromEvent needs a way for it to attach and detach from the event. The h is a promise that says "hey, FromEvent, if you can provide a handler, when you need it in the future, I promise that this code will attach it correctly." Or, detach, as the case may be.
Now, just to be a bit pedantic, your code should actually be:
IObservable<EventPattern<EventArgs>> appActivated =
Observable
.FromEventPattern<EventHandler, EventArgs>(
h => Application.Current.Activated += h,
h => Application.Current.Activated -= h);
Now that I have a IObservable<EventPattern<EventArgs>> I can rewrite SomeMethod to take this as a parameter and write it like this:
public IDisposable SomeMethod(IObservable<EventPattern<EventArgs>> appActivated)
{
return appActivated.Subscribe(ep => { /* Handler Code */ });
}
Now all of the power of Rx can be seen. The .Subscribe method doesn't need any reference to the original event's containing object, but it will ultimately call h => Application.Current.Activated += h to attach and h => Application.Current.Activated -= h to detach as and when it needs. I can now effectively pass around events as first-class types in .NET.

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

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.

Altering the ObservableCollection according to FileSystemWatcher change notification

I'm trying to update my ObservableCollection as the FileSystemWatcher notifies changes. I know this is not possible because of cross thread operations.
So i would like to get the name of the file created/deleted/renamed when the event is fired and update it in the UI thread once the event is completed, as we do in BackgroundWorker. Can anyone tell me how to do this?
Also tell me where i should define and start this FileSystemWatcher. Currently i've defined it in the MainViewModel.
P.S.: I've seen similar questions in SO, but didn't get a clear picture
Thanks In Advance,
Veer
I would think the main view model is the right place to define the FileSystemWatcher. As for the threading issues, this is the easy way:
_watcher = new FileSystemWatcher(path);
_watcher.Created += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Created event
};
_watcher.Changed += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Changed event
};
_watcher.Renamed += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Renamed event
};
_watcher.Deleted += (obj, e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
{
// Code to handle Deleted event
};
// ...
_watcher.EnableRaisingEvents = true;
Each of the "Code to handle" will execute within the UI thread so it can update the ObservableCollection. Note that the FileSystemEventArgs "e" is available within this code.
If you prefer to use separate event handler methods you can call them from the above code or use this convenient shortcut:
var switchThread =
(FileSystemEventHandler handler) =>
(object obj, FileSystemEventArgs e) =>
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))
_watcher = new FileSystemWatcher(path);
_watcher.Created += switchThread(OnCreated);
_watcher.Changed += switchThread(OnChanged);
_watcher.Deleted += switchThread(OnDeleted);
_watcher.Renamed += switchThread(OnRenamed);
_watcher.EnableRaisingEvents = true;
where OnCreated, OnChanged, OnDeleted, and OnRenamed are normal event handler methods with the normal signature, for example:
void OnChanged(object sender, FileSystemEventArgs e)
{
// Code to handle Changed event
}
Personally I prefer the first way of doing it because I don't like creating four extra 1-line methods.
Note that your view model will need to know which Dispatcher to call back on. The easiest way to do this is to derive your view model from DispatcherObject, as assumed above. Another way is for the view model's constructor or the method that registers the FileSystemWatcher events to store a copy of Dispatcher.Current in a local field or local variable, then use that for the .BeginInvoke calls.
Also note that you can use exactly the same code in your view code-behind instead of in your view model if you prefer.
public void SomeActionToBeInvokedOnTheMainThread()
{
if (someControl.Dispatcher.CheckAccess())
{
// you can modify the control
}
else
{
someControl.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(SomeActionToBeInvokedOnTheMainThread)
);
}
}
I used Ray B.'s approach but had to modify things slightly and thought I'd post an update here to maybe save others some time.
My VS2010/.NET 4.0 WPF project was throwing the error:
Cannot assign lambda expression to an implicitly-typed local variable
After some tweaking I came up with the following. Note the additional var defined to handle the Renamed event:
var switchThreadForFsEvent = (Func<FileSystemEventHandler, FileSystemEventHandler>)(
(FileSystemEventHandler handler) =>
(object obj, FileSystemEventArgs e) =>
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))));
var switchThreadForFsRenameEvent = (Func<RenamedEventHandler, RenamedEventHandler>)(
(RenamedEventHandler handler) =>
(object obj, RenamedEventArgs e) =>
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
handler(obj, e))));
_fileSystemWatcher = new FileSystemWatcher(documentCollectionPath);
_fileSystemWatcher.Created += switchThreadForFsEvent(OnFileCreated);
_fileSystemWatcher.Deleted += switchThreadForFsEvent(OnFileDeleted);
_fileSystemWatcher.Renamed += switchThreadForFsRenameEvent(OnFileRenamed);
_fileSystemWatcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
_fileSystemWatcher.IncludeSubdirectories = true;
_fileSystemWatcher.EnableRaisingEvents = true;

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# - 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