Why wrap event assignments in async anonymous functions? - c#

Is there any point in wrapping event assignments in anonymous async functions?
Lets say this code is in some adapter class:
public event Action<int> someAction;
The following code is in some other class that sets the action:
Example 1:
_someAdapter.someAction += async (someParameter) =>
{
await HandleAction(someParamter);
};
In this case HandleAction has async Task return type.
Example 2:
_someAdapter.someAction += HandleAction;
In this case HandleAction has async void return type.
The same question applies to button click event handlers etc. I have seen examples of both and was wondering why this gets wrapped sometimes. From my testing there doesn't seem to be any difference.

I believe that using an anonymous handler wrapper you'll be able to let the C# Garbage Collector just "unhook" and destroy the handler on this (on example 1) when it is about to be destroyed.
Event handlers outside the this (it isn't the case in your example) would have special attention and wrap it looks a good choice.
If this will live a long time and there is some possibility of you have to hook that event again you should use another strategy to avoid memory leak like ones discussed on this question
The return types differences are related to exception handling and it's ok to use an async void on top-level methods and async event handlers.
I hope it helps.

In your example, there would be likely be no noticeable difference. This is more about coding standards and best practices. In general, it is not recommended that you create 'async void' functions, if you can avoid it. The purpose of that feature is to allow async code in functions that can't change their signature (like overrides). An 'async void' function has disadvantages like swallowing exceptions and being less composable.
If, for instance, you wanted to call HandleAction from another place/method (often this is the reason for using a named method instead of an anonymous function), you would not be able to await it unless it returns Task.
Also, if HandleAction threw an exception, you would not be able to catch it if you can't await it, so you better be sure it will handle all exceptions internally.

I won't recommend to use an anonymes delegate as an event handler. The reason is that it might come to cycling references and thus the garbage collector won't be able to free up memory - so called memory leak.
Especially in the Xamarin-world, where the managed garbage collector often won't know the real size of an object, developers should have an eye on memory and allocations their applications needs.
By avoiding anonymes delegates you are able to break the cycle simple by removing the event handler assignment.

I can't comment on your adapter handlers, but... seeing as you say "The same question applies to...", the answer might be the same as for button click event handlers, etc, which is (arguably the largest benefit of async in UI applications) - you get to perform expensive async operations in the handlers off the UI thread.
E.g.
_button.Click += async (...) =>
{
int answer = await ExpensiveHttpResultThatTakes10Seconds();
_answer.Text = answer.ToString();
};
If that wasn't async, the UI would freeze up for 10 seconds, not responding to clicks, keys, etc.
Because it is async, the UI remains responsive during those 10 seconds, as the await is non-blocking, processing UI events and even other event handlers.

Related

From sync to async scenario

I have this event handler:
private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
{
var canShutdown = lifetime.CanShutdown();
e.Cancel = !canShutdown;
}
Now, due to design decisions the CanShutdown method has changed from bool to Task<bool>
Task<bool> CanShutDown()
{
//...
}
So, I need to modify the event handler like this:
private async void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
{
var canShutdown = await lifetime.CanShutdown();
e.Cancel = !canShutdown;
}
I've read many times that async void methods have many problems, like unhandled exceptions being thrown directly inside the SynchronizationContext. But one of the valid usages for them are event handlers. This is an event handler. Isn't it?
BUT, I wonder if that code is free of undesired consequences after the "migration".
My concern is that the handler modifies the value of e.Cancel.
A colleague has told me that this will happen:
After await, the caller to that method isn't awaiting. It assumes synchronous execution, so it immediately reads e.Cancel, and that hasn't been set yet.
That is a problem inside event handler: You realize as soon as the await keyword is hit, the code that called ShutdownRequested.Invoke() immediately returns. The value it will read might not be up-to-date.
I'm afraid my colleague has his point. So, it seems this approach is broken. But I still don't see how to fix that.
How to deal with the EventArgs being shared by sync and async code?
I've read many times that async void methods have many problems, like unhandled exceptions being thrown directly inside the SynchronizationContext. But one of the valid usages for them are event handlers.
Yes. In fact, throwing exceptions on the SynchronizationContext is actually deliberate behavior specifically to emulate the behavior of event handlers.
One of the primary problems with async void method is that it's not easy to determine when the async void method has completed. Which is exactly the problem your colleague is pointing out.
This is an event handler. Isn't it?
Sort of.
Take a step back and consider the design patterns being used. The Observer pattern is a way to notify observers of state changes. The Observer pattern is a clear fit for "events" in OOP: any number of observers may subscribe to state change notifications.
This kind of "shutdown" notification is not just a notification, though. It also has a return value. Generally, this is the Strategy pattern. The Strategy pattern is not a good fit for events in OOP. However, many times the Strategy pattern is (mis-)implemented with an event; this is a common design mistake in OOP languages.
So, is it an event handler? Technically, yes. Should it be an event handler? Probably not.
In the synchronous world, implementing the Strategy pattern with events is often "close enough". Sometimes there's some confusion about how the return value should be handled in case there are multiple event subscribers, but in general this kind of design mistake goes unnoticed. Until async comes along, and suddenly the design mistake of using events for the Strategy pattern becomes more apparent.
But I still don't see how to fix that.
I describe a few possibilities on my blog.
If you control OnShutdownRequested and ShutdownRequestedEventArgs, then you can use deferrals. It's a bit complex to set up, but it allows both synchronous and asynchronous handlers (as long as the handlers use a deferral), and the code that raises the event can (asynchronously) wait for all handlers to complete before retrieving the results.
If shutdown is the only event you have to worry about, then one common trick is to always set Cancel to true, do the asynchronous work, and then if the shutdown is permitted, explicitly do a shutdown at the end of that asynchronous work.
Your colleague is correct, the posted example code will most likely not work as intended.
I would suggest making ShutdownRequestedEventArgs contain something like a List<Task<bool>>, so the caller can await all the task to determine if any of them wants to cancel before shutting down. This might also include a timeout, so that some hanged task does not block the process forever. This moves the problem from the handler of the event to the caller, that hopefully is in a better position to deal with the problem.
Another possibility could be to wait for the task synchronously:
private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
{
var canShutdown = lifetime.CanShutdown().Result;
e.Cancel = !canShutdown;
}
But this may be dangerous in a UI program. If the ShutdownRequested is requested on the UI thread, and CanShutdown needs to execute any code on the UI thread, then the program will deadlock. And this is fairly likely if CanShutdown is not written specifically to avoid this. See configureAwait for more details .
You might also just revert to the synchronous solution. An event like ShutdownRequested does not sound like it is a good fit for an asynchronous solution. I would have expected that such an event would require a immediate response. But I do not know the background of your application or why the method was changed in the first place, so there might very well be good reasons for it.

Am I obliged to call EndPeek after using BeginPeek?

I have a Windows service that processes a private, local message queue (MSMQ). When it starts, it registers an event handler for PeekCompleted on the queue, and it then calls the asynchronous BeginPeek() to wait for a message to arrive.
protected override void OnStart(string[] args)
{
if (String.IsNullOrWhiteSpace(args[0]))
return;
queue = new MessageQueue(args[0]);
queue.Formatter = new BinaryMessageFormatter();
queue.PeekCompleted += new PeekCompletedEventHandler(OnPeekCompleted);
queue.BeginPeek();
}
Once a message arrives, my goal is to obviously process that message. My code currently has a queue.Receive() method to get the message, contained within a transaction so the message gets put back on the queue in case of errors during processing. BeginPeek() is called again to restart the cycle.
private static void OnPeekCompleted(Object source, PeekCompletedEventArgs asyncResult)
{
try
{
MessageQueue q = (MessageQueue)source;
using (MessageQueueTransaction trans = new MessageQueueTransaction())
{
trans.Begin();
Message msg = q.Receive(trans);
ProcessMessage(msg);
trans.Commit();
}
// Restart the asynchronous peek operation.
q.BeginPeek();
}
catch (MessageQueueException qEx)
{
// TODO: Walk it off.
}
return;
}
Do I, at any point, need to call EndPeek() on the queue ?
Maybe to avoid memory leaks, like this question alludes to ? I'm pretty sure I don't have to, but the documentation isn't very clear on that. It just doesn't feel 100% right to 'begin' something without 'ending' it :)
Btw: I could replace the Receive() line with Message msg = q.EndPeek(asyncResult.AsyncResult), which equally fetches me the message, but it doesn't remove the message from the queue.
Giving a proper answer to this question takes some effort, because the short answer ("no") could be misleading.
Does the API description explicitly say you must call EndPeek() for every call to BeginPeek()? Not in any topic I could find, and not only that, it appears to state the opposite here:
To use BeginPeek, create an event handler that processes the results
of the asynchronous operation, and associate it with your event
delegate. BeginPeek initiates an asynchronous peek operation; the
MessageQueue is notified, through the raising of the PeekCompleted
event, when a message arrives in the queue. The MessageQueue can then
access the message by calling EndPeek(IAsyncResult) or by retrieving
the result using the PeekCompletedEventArgs.
(Emphasis mine.) This seems to say that you can either use .EndPeek() or just directly get the message from the event args with no obligation to call .EndPeek().
Alright, so does the implementation mandate that you call .EndPeek() in order to make things work correctly? At least for the System.Messaging implementation in .NET 4.0, the answer is no. When you call .BeginPeek(), an asynchronous operation is allocated and a callback is registered for completion. The unmanaged resources associated with this operation are partially cleaned up in this callback, and only then is the event handler called. .EndPeek() does not actually do any cleanup -- it merely waits for the operation to complete if it hasn't yet, checks for errors, and returns the message. So it is indeed true that you can either call .EndPeek() or just access the message from the event args, or do nothing at all -- it will all work just as poorly.
Poorly, yes -- note that I said "partially cleaned up". The implementation of MessageQueue has a problem in that it allocates a ManualResetEvent for every asynchronous operation, but never disposes it, leaving this entirely up to the garbage collector -- something .NET developers are often excoriated for doing, but of course Microsoft's own developers aren't perfect either. I haven't tested whether the OverlappedData leak described in this question is still relevant, nor is it immediately obvious from the source, but it would not surprise me.
The API has other warning signs that its implementation may leave something to be desired, most prominently that it does not follow the established .Begin...() / .End...() pattern for asynchronous operations but introduces event handlers in the middle, producing a strange hybrid I've never see anywhere else. Then there's the very dubious decision of making the Message class inherit from Component, which adds considerable overhead to every instance and raises the question of when and how it should be disposed... all in all, not Microsoft's best work.
Now, does all this mean you're not "obliged" to call .EndPeek()? Yes, in the sense that calling it or not calling it makes no functional difference with regards to resource cleanup or correctness. But with all that said, my advice is still to call it anyway. Why? Because anyone who is familiar with how the asynchronous operation pattern works in other .NET classes would expect the call to be there, and not putting it there looks like a bug that could lead to resource leaks. If there is a problem with the application, such a person might reasonably spend some fruitless effort looking at "problem code" that isn't. Given that a call to .EndPeek() has negligible overhead compared to the rest of the machinery, I'd say the savings in programmer surprise more than make up for the costs. A possible alternative is to insert a comment instead, explaining why you're not calling .EndPeek() -- but in all probability this still takes more programmer cycles to grasp than just calling it.
In theory, another reason for calling it is that the semantics of the API could change in the future to make the call to .EndPeek() necessary; in practice, this is very unlikely to happen because Microsoft is traditionally reluctant to make breaking changes like this (code that previously and reasonably did not call .EndPeek() would stop working) and the existing implementation already contravenes established practice.

Use cases for async void methods, revisited

I'm aware that the best practice is to avoid async void methods for anything but async event handlers, and there is quite strong expert opinion against other use cases. I was however just involved in a brief discussion about usefulness of async void methods and I've got a couple of questions:
How does the Framework keep track of pending async void methods, including event handlers? Is there possibly a way to obtain the current list of them or cancel them (EDITED: tracking is probably possible by installing a custom SynchronizationContext)?
Are they any useful for fire-and-forget logging scenarious? I think they actually may be, as long as the correct time-stamp is preserved at the beginning of the method, while it still executes synchronously.
How does the Framework keep track of pending async void methods, including event handlers?
The framework doesn't do anything special to keep track of async void methods. They're just like any other async method.
Also, your method either has a proper signature or it doesn't; event handlers do not care and have no logic to detect or work with async specifically.
A custom scheduler would be able to keep track of running tasks, but not have any specific knowledge if one is from an async void method or not. I don't think this is the right solution anyway -- if you find yourself needing to keep track of an async void method, you need to rethink your design.
Are they any useful for fire-and-forget logging scenarios? I think they actually may be, as long as the correct time-stamp is preserved
I don't know what you mean by a timestamp?
Async void is fine for any method where the caller will either never need to care about the result of the method call, or where it is being notified of the result elsewhere. These cases should be very exceedingly rare.
Fire-and-forget might be one such scenario, though I feel people often misuse fire-and-forget and end up just hiding important bugs from themselves.
Regarding logging scenarios, here are two scenarios, with async-void being suitable for the first but less suitable for the second.
1) Logging the outcome of a long-running operation:
public static async void LogCompletion(Task operation, string title)
{
try
{
await operation.ConfigureAwait(false);
Log.Info($"{title} completed succesfully");
}
catch (Exception ex)
{
Log.Error($"{title} failed", ex);
}
}
This usage resembles an async event handler, since the completion of an asynchronous operation is conceptually similar to the raising of an event. So this method essentially "handles" the completion "event" of a specific task. Converting this async-void method to an async Task LogCompletionAsync method wouldn't bring many benefits. It is true that an exception inside the LogCompletion method will crash the process, but the only possibility for an exception to occur is if the Log.Error throws. But if your logging framework starts throwing exceptions, your application is not going to stay alive for long anyway. And the sooner you learn about it the better, to start searching ASAP for a better logging framework.
2) Logging per se:
public static async void Log(string message)
{
try
{
await File.AppendAllTextAsync(GetLogFilePath(),
DateTime.Now.ToString() + " " + message + "\r\n");
}
catch { }
}
This usage resembles calling an asynchronous method in a fire-and-forget fashion. Although it's not a terrible usage of async-void, it is a quite primitive and unsophisticated way of implementing logging in general. And it is quite inadvisable to try implementing it in the first place, since there are many high-quality implementations out there, available for free.
Are they any useful for fire-and-forget logging scenarious?
Conceptually, I would say so, but if a task has an exception and it isn't being handled by waiting on it or accessing its Exception property which doesn't happen in an async void method it will tear down your application.
So I would avoid that.

Why are Subjects not recommended in .NET Reactive Extensions?

I am currently getting to grips with the Reactive Extensions framework for .NET and I am working my way through the various introduction resources I've found (mainly http://www.introtorx.com)
Our application involves a number of hardware interfaces that detect network frames, these will be my IObservables, I then have a variety of components that will consume those frames or perform some manner of transform on the data and produce a new type of frame. There will also be other components that need to display every n'th frame for example.
I am convinced that Rx is going to be useful for our application, however I am struggling with the implementation details for the IObserver interface.
Most (if not all) of the resources I have been reading have said that I should not implement the IObservable interface myself but use one of the provided functions or classes.
From my research it appears that creating a Subject<IBaseFrame> would provide me what I need, I would have my single thread that reads data from the hardware interface and then calls the OnNext function of my Subject<IBaseFrame> instance. The different IObserver components would then receive their notifications from that Subject.
My confusion is coming from the advice give in the appendix of this tutorial where it says:
Avoid the use of the subject types. Rx is effectively a functional programming paradigm. Using subjects means we are now managing state, which is potentially mutating. Dealing with both mutating state and asynchronous programming at the same time is very hard to get right. Furthermore, many of the operators (extension methods) have been carefully written to ensure that correct and consistent lifetime of subscriptions and sequences is maintained; when you introduce subjects, you can break this. Future releases may also see significant performance degradation if you explicitly use subjects.
My application is quite performance critical, I am obviously going to test the performance of using the Rx patterns before it goes in to production code; however I am worried that I am doing something that is against the spirit of the Rx framework by using the Subject class and that a future version of the framework is going to hurt performance.
Is there a better way of doing what I want? The hardware polling thread is going to be running continuously whether there are any observers or not (the HW buffer will back up otherwise), so this is a very hot sequence. I need to then pass the received frames out to multiple observers.
Any advice would be greatly appreciated.
Ok,
If we ignore my dogmatic ways and ignore "subjects are good/bad" all together. Let us look at the problem space.
I bet you either have 1 of 2 styles of system you need to ingrate to.
The system raises an event or a call back when a message arrives
You need to poll the system to see if there are any message to process
For option 1, easy, we just wrap it with the appropriate FromEvent method and we are done. To the Pub!
For option 2, we now need to consider how we poll this and how to do this effciently. Also when we get the value, how do we publish it?
I would imagine that you would want a dedicated thread for polling. You wouldn't want some other coder hammering the ThreadPool/TaskPool and leaving you in a ThreadPool starvation situation. Alternatively you don't want the hassle of context switching (I guess). So assume we have our own thread, we will probably have some sort of While/Sleep loop that we sit in to poll. When the check finds some messages we publish them. Well all of this sounds perfect for Observable.Create. Now we probably cant use a While loop as that wont allow us to ever return a Disposable to allow cancellation. Luckily you have read the whole book so are savvy with Recursive scheduling!
I imagine something like this could work. #NotTested
public class MessageListener
{
private readonly IObservable<IMessage> _messages;
private readonly IScheduler _scheduler;
public MessageListener()
{
_scheduler = new EventLoopScheduler();
var messages = ListenToMessages()
.SubscribeOn(_scheduler)
.Publish();
_messages = messages;
messages.Connect();
}
public IObservable<IMessage> Messages
{
get {return _messages;}
}
private IObservable<IMessage> ListenToMessages()
{
return Observable.Create<IMessage>(o=>
{
return _scheduler.Schedule(recurse=>
{
try
{
var messages = GetMessages();
foreach (var msg in messages)
{
o.OnNext(msg);
}
recurse();
}
catch (Exception ex)
{
o.OnError(ex);
}
});
});
}
private IEnumerable<IMessage> GetMessages()
{
//Do some work here that gets messages from a queue,
// file system, database or other system that cant push
// new data at us.
//
//This may return an empty result when no new data is found.
}
}
The reason I really don't like Subjects, is that is usually a case of the developer not really having a clear design on the problem. Hack in a subject, poke it here there and everywhere, and then let the poor support dev guess at WTF was going on. When you use the Create/Generate etc methods you are localizing the effects on the sequence. You can see it all in one method and you know no-one else is throwing in a nasty side effect. If I see a subject fields I now have to go looking for all the places in a class it is being used. If some MFer exposes one publicly, then all bets are off, who knows how this sequence is being used!
Async/Concurrency/Rx is hard. You don't need to make it harder by allowing side effects and causality programming to spin your head even more.
In general you should avoid using Subject, however for the thing you are doing here I think they work quite well. I asked a similar question when I came across the "avoid subjects" message in Rx tutorials.
To quote Dave Sexton (of Rxx)
"Subjects are the stateful components of Rx. They are useful for when
you need to create an event-like observable as a field or a local
variable."
I tend to use them as the entry point into Rx. So if I have some code that needs to say 'something happened' (like you have), I would use a Subject and call OnNext. Then expose that as an IObservable for others to subscribe to (you can use AsObservable() on your subject to make sure nobody can cast to a Subject and mess things up).
You could also achieve this with a .NET event and use FromEventPattern, but if I'm only going to turn the event into an IObservable anyway, I don't see the benefit of having an event instead of a Subject (which might mean I'm missing something here)
However, what you should avoid quite strongly is subscribing to an IObservable with a Subject, i.e. don't pass a Subject into the IObservable.Subscribe method.
Often when you're managing a Subject, you're actually just reimplementing features already in Rx, and probably in not as robust, simple and extensible a way.
When you're trying to adapt some asynchronous data flow into Rx (or create an asynchronous data flow from one that's not currently asynchronous), the most common cases are usually:
The source of data is an event: As Lee says, this is the simplest case: use FromEvent and head to the pub.
The source of data is from a synchronous operation and you want polled updates, (eg a webservice or database call): In this case you could use Lee's suggested approach, or for simple cases, you could use something like Observable.Interval.Select(_ => <db fetch>). You may want to use DistinctUntilChanged() to prevent publishing updates when nothing has changed in the source data.
The source of data is some kind of asynchronous api that calls your callback: In this case, use Observable.Create to hook up your callback to call OnNext/OnError/OnComplete on the observer.
The source of data is a call that blocks until new data is available (eg some synchronous socket read operations): In this case, you can use Observable.Create to wrap the imperative code that reads from the socket and publishes to the Observer.OnNext when data is read. This may be similar to what you're doing with the Subject.
Using Observable.Create vs creating a class that manages a Subject is fairly equivalent to using the yield keyword vs creating a whole class that implements IEnumerator. Of course, you can write an IEnumerator to be as clean and as good a citizen as the yield code, but which one is better encapsulated and feels a neater design? The same is true for Observable.Create vs managing Subjects.
Observable.Create gives you a clean pattern for lazy setup and clean teardown. How do you achieve this with a class wrapping a Subject? You need some kind of Start method... how do you know when to call it? Or do you just always start it, even when no one is listening? And when you're done, how do you get it to stop reading from the socket/polling the database, etc? You have to have some kind of Stop method, and you have to still have access not just to the IObservable you're subscribed to, but the class that created the Subject in the first place.
With Observable.Create, it's all wrapped up in one place. The body of Observable.Create is not run until someone subscribes, so if no one subscribes, you never use your resource. And Observable.Create returns a Disposable that can cleanly shutdown your resource/callbacks, etc - this is called when the Observer unsubscribes. The lifetimes of the resources you're using to generate the Observable are neatly tied to the lifetime of the Observable itself.
The quoted block text pretty much explains why you shouldn't be using Subject<T>, but to put it simpler, you are combining the functions of observer and observable, while injecting some sort of state in between (whether you're encapsulating or extending).
This is where you run into trouble; these responsibilities should be separate and distinct from each other.
That said, in your specific case, I'd recommend that you break your concerns into smaller parts.
First, you have your thread that is hot, and always monitoring the hardware for signals to raise notifications for. How would you do this normally? Events. So let's start with that.
Let's define the EventArgs that your event will fire.
// The event args that has the information.
public class BaseFrameEventArgs : EventArgs
{
public BaseFrameEventArgs(IBaseFrame baseFrame)
{
// Validate parameters.
if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");
// Set values.
BaseFrame = baseFrame;
}
// Poor man's immutability.
public IBaseFrame BaseFrame { get; private set; }
}
Now, the class that will fire the event. Note, this could be a static class (since you always have a thread running monitoring the hardware buffer), or something you call on-demand which subscribes to that. You'll have to modify this as appropriate.
public class BaseFrameMonitor
{
// You want to make this access thread safe
public event EventHandler<BaseFrameEventArgs> HardwareEvent;
public BaseFrameMonitor()
{
// Create/subscribe to your thread that
// drains hardware signals.
}
}
So now you have a class that exposes an event. Observables work well with events. So much so that there's first-class support for converting streams of events (think of an event stream as multiple firings of an event) into IObservable<T> implementations if you follow the standard event pattern, through the static FromEventPattern method on the Observable class.
With the source of your events, and the FromEventPattern method, we can create an IObservable<EventPattern<BaseFrameEventArgs>> easily (the EventPattern<TEventArgs> class embodies what you'd see in a .NET event, notably, an instance derived from EventArgs and an object representing the sender), like so:
// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();
// Create the observable. It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
Of course, you want an IObservable<IBaseFrame>, but that's easy, using the Select extension method on the Observable class to create a projection (just like you would in LINQ, and we can wrap all of this up in an easy-to-use method):
public IObservable<IBaseFrame> CreateHardwareObservable()
{
// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();
// Create the observable. It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
// Return the observable, but projected.
return observable.Select(i => i.EventArgs.BaseFrame);
}
It is bad to generalize that Subjects are not good to use for a public interface.
While it is certainly true, that this is not the way a reactive programming approach should look like, it is definitively a good improvement/refactoring option for your classic code.
If you have a normal property with an public set accessor and you want to notify about changes, there speaks nothing against replacing it with a BehaviorSubject.
INPC or additional other events are just not that clean and it personally wears me off.
For this purpose you can and should use BehaviorSubjects as public properties instead of normal properties and ditch INPC or other events.
Additionally the Subject-interface makes the users of your interface more aware about the functionality of your properties and are more likely to subscribe instead of just getting the value.
It is the best to use if you want others to listen/subscribe to changes of a property.

Is there a reason to remove a method from an event after it has been invoked in Silverlight?

Recently I have come across an increasing number of people who have code similar to the following:
private AsynchronousReader r;
public SynchronousReader()
{
r = new AsynchronousReader();
// My practice is to put this here
// and then never remove it and never add it again
// thus cleaning up the code and preventing constant add/remove.
//r.ReadCompleted += this.ReadCompletedCallback;
}
private ReadCompletedCallback()
{
// Remove the callback to "clean things up"...
r.ReadCompleted -= this.ReadCompletedCallback;
// Do other things
}
public Read()
{
r.ReadCompleted += this.ReadCompletedCallback;
// This call completes asynchronously and later invokes the above event
r.ReadAsync();
r.WaitForCompletion();
}
Folks say that this practice is better than the one I indicated above and have given several reasons specific to Silverlight. They state it prevents memory leaks, threading issues, and even that it is the normal practice.
I have not done much Silverlight, but it seems silly to do this still.
Are there any specific reasons one would use this method instead of just rigging up the callback in the constructor once and for the lifetime of the object?
This is as simple as I could make my example. Ignore the fact that it's a sort of wrapper that turns an asynchronous object into a synchronous one. I'm only curious about the way events are added and removed.
In the case you mention it would make sense to hook it up once, but potentially the objects (parent and/or child) may not get garbage collected as the event handlers still reference them.
According to Marc Gavel here
i.e. if we have:
publisher.SomeEvent += target.SomeHandler;
then "publisher" will keep "target" alive, but "target" will not keep
"publisher" alive.
A more important point to bear in mind might be the lifespan of the child object. If it is the same as the parent, then one-off subscription in the constructor makes more sense. If it is dynamic you will likely want to remove the handlers as I have seen them leak (resulting in multiple callbacks).
Note: If the constructor-only method turns out to leak objects, you can always put an unsubscribe in the Dispose() I guess, but I can't say I have ever seen that.
It sounds like you have two issues:
You're attempting to reuse an object that really should only be used once.
That object needs to get properly cleaned up.
You should really either only use an instance of the SynchronousReader object only once (thus avoiding the two async calls racing with one failing to finish like you mentioned elsewhere) or you should implement IDisposable in order to unsubscribe from the event and prevent the memory leak.
A third solution might be possible: keep the single instance of SynchronousReader, but each call to SynchronousReader.Read would create a new instance of AsynchronousReader (rather than storing it as a private field within the instance). Then you could keep most of the code above which you don't like, but which properly handles event subscriptions.

Categories