The WinRT CoreDispatcher has the RunAsync method which, actually doesn't take a state variable.
Translation: Every single notification that happens by posting to the Dispatcher in most common scenarios ends up in an allocation internally due to the closure. Its quite concerning that a simple and important design was overlooked.
Eg: A simple common example implementing an INotifyPropertyChanged requires a method that ends up something like this:
protected virtual void NotifyPropertyChanged(
[CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
// Check access first, and then at some point pass it along.
Dispatcher.RunAsync(() =>
handler(this, new PropertyChangedEventArgs(propertyName)));
}
}
Now, every time a simple prop changed notification is called, a new class is allocated by the compiler behind the scenes, which is terrible for a lot of notifications. This makes falling back to SynchronizationContext.Post, a more efficient option when there are lot of notifications considering it has a state variable that the handler, and propertyName can be passed along with.
Any suggestions or thoughts on how to work with the Dispatcher in this scenario would be much appreciated.
I don't think you need to worry about it. Using a closure is likely to be just fine; I doubt you'll observe any significant performance decrease.
Note that in other cases where you can pass parameters to the invoked method, you still wind up with an allocation. At a minimum, an
object[]
has to be allocated to contain the parameters. In addition, value type parameters wind up having to be boxed: more allocations.So it seems to me that a closure is at worst the same, and in some scenarios can be more efficient allocation-wise, since value types don't have to be boxed in that scenario.
If, against all odds, you do find yourself in a scenario where the allocations are hurting your performance, you can implement your own closure explicitly and reuse the instance. I.e. create a class that is explicitly used, which contains any variables that would normally be captured, and which contains the code you want to execute. Then allocate one of those (or several, in a pool) and reuse the instance(s) for each invocation.
But really, I doubt you'll ever find a compelling reason to go to all that trouble.