WinRT and the syntactic sugar around .NET event handlers
If you've watched the great number of videos available from the Build conference, you've probably noticed that the layer between .NET and WinRT is very thin.
So thin that in permeates through to C# 5.0, even though it's not immediately visible to the naked eye.
Also, that Windows 8 developer preview is pretty stable... I'm writing this blog post using it, and it's pretty good :) (lovin' the inline spell checker, everywhere !!)
What about WinRT ?
The Windows Runtime has been explained here, there and by Miguel de Icasa (and there too by Julien Dollon), but to summarize in other words, WinRT is (at least for now) the new way to communicate with the Windows Core, with an improved developer experience. It's the new preferred (and only, as far as I know) way to develop Metro style applications, in many languages like C#/F#/VB, C++, JavaScript and more...
The API is oriented toward developing tablet applications, with the power and connectivity limitation that kind of platform has, plus the addition of what makes Windows Phone so interesting. That means Live Tiles, background agents, background transfers, XAML, background audio, social APIs, camera, sensors, location, and new features like sharing and search contracts, ...
My favorite part of all this is the new addition of a rule that make a LOT of sense : If an API call nominally takes more than 50ms to execute, then it's an asynchronous api call. But not using the ugly Begin/End pattern, rather through the nice async/await pattern, WinRT style (I'll elaborate on that in a later post). I've even started to apply that rule to my existing development with the Reactive Extensions (And that's yet an other later post).
Microsoft has taken the approach of cleaning up the .NET framework with the ".NET Core" profile. For instance, the new TypeInfo class now separates the introspection part from the type safety part that were historically merged in the System.Type type. This segregation limits the loading of type metadata only when necessary, and not when just doing a simple typeof(). Now, the System.Type type is fairly simple, and to get back all the known methods like GetMethods() or GetProperties() there's an extension method called Type.GetTypeInfo() in System.Reflection that gives back all the reflection side.
There are a lot of other differences, I'll discuss in a later post. (yeah, that's a lot to talk about !)
For the .NET developer, WinRT takes the form of *.winmd files that follow the .NET standard metadata format (kind of like TLB files on steroids, if you know what I mean...). These files can be directly referenced from .NET code like any other assembly, it's then very easy to call the underlying Windows platform. No more P/Invoke.
Just before you start freaking out, WinRT does not replace the standard .NET 4.5 full platform you already know, remember that. That's just a new profile, much like Windows Phone or Xbox 360 are profiles, but targeted at Metro style applications. (It's not applications anymore, it's apps :) just so you know...)
But how thin is the layer, really ?
To accommodate all these languages, compromises had to be made and underneath, WinRT is native code. Native code means no garbage collection, limited value types, a pretty different exception handling (SEH), and so on.
The CLR and C# compiler teams have made a great job at trying to hide all this but there are still some corner cases where you can see those differences appear.
For instance, you'll find that there are two EventHandler types : the existing System.EventHandler, and the new Windows.UI.Xaml.EventHandler. What's the difference ? See for yourself :
namespace System { [ComVisible(true)] public delegate void EventHandler(object sender, EventArgs e); }
And the other one :
namespace Windows.UI.Xaml { // Summary: // Represents a basic event handler method. [Version(100794368)] [WebHostHidden] [Guid(3817893849, 19739, 19144, 164, 60, 195, 185, 8, 116, 39, 152)] public delegate void EventHandler(object sender, object e); }
The difference is subtle, but it's there : the second parameter is an object. This is kind of troubling, and having to juggle between the two is going to be a bit messy. That's going to be the forced return of conditional compilation and the myriads of #if and #endif...
But the difference does not stop here though. Let's look at how the WinRT handler can be used :
public class MyCommand : Windows.UI.Xaml.Input.ICommand { public event Windows.UI.Xaml.EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { } public void Execute(object parameter) { } }
Translates to this, after the compiler does its magic :
using System.Runtime.InteropServices.WindowsRuntime; public class MyCommand : Windows.UI.Xaml.Input.ICommand { public event Windows.UI.Xaml.EventHandler CanExecuteChanged { add { return this.CanExecuteChanged.AddEventHandler(value); } remove { this.CanExecuteChanged.RemoveEventHandler(value); } } public bool CanExecute(object parameter) { } public void Execute(object parameter) { } public MyCommand() { this.CanExecuteChanged = new EventRegistrationTokenTable(); } }
The delegates are not stored in a multicast delegate instance like they used to be, but are now stored in an EventRegistrationTokenTable type instance, and provides a return value for the add handler ! Also, the remove handler "value" is a EventRegistrationToken instance.
That construct is so new that even the intellisense engine is mistaken by this new syntax if you try to write it by yourself, but it compiles correctly.
The return value is of type EventRegistrationToken, and I'm guessing that it must be something WinRT must keep track of to call marshaled managed delegates.
The calling part is also very interesting, if you try to register to that event :
// Before MyCommand t = new MyCommand(); t.CanExecuteChanged += (s, e) => { };
// After MyCommand t = new MyCommand(); WindowsRuntimeMarshal.AddEventHandler( new Func(t.add_CanExecuteChanged) , new Action(t.remove_CanExecuteChanged) , delegate(object s, object e) { } );
Quite different, isn't it ?
But this syntactic sugar seems only to be related to the fact that the WinRT EventHandler delegate type is exposed as a implemented interface member, like in ICommand. It does not appear if it is used somewhere else.
Cool. Why should care ?
Actually, you may not care at all, unless you write ICommand implementations.
If you write a command, and particularly ICommand wrappers or proxies, you may want to write your own add/remove handlers and to be able to do so, you'll need to return that EventRegistrationToken too, and map that token to your delegate.
Here's what I came up with :
public class MyCommand : Windows.UI.Xaml.Input.ICommand { EventRegistrationTokenTable _table = new EventRegistrationTokenTable(); Dictionary _reverseTable = new Dictionary(); public event EventHandler CanExecuteChanged { add { var token = _table.AddEventHandler(value); _reverseTable[token] = value; // do something with value return token; } remove { // Unregister value RemoveMyHandler(_reverseTable[value]); _table.RemoveEventHandler(value); } } }
All this because the EventRegistrationTokenTable does not expose a bi-directional mapping between event handlers and their tokens.
But remember, WinRT and Dev11 are in Developer Preview state. That's not even beta. This will probably change !