In the latest video by Rx team Bart De Smet: Rx Update – .NET 4.5, Async, WinRT I saw that WinRT events exposed to .NET by some really strange metadata, more preciesly – add_/remove_ pair methods signature:
EventRegistrationToken add_MyEvent(EventHandler<MyEventArgs> handler) { … }
void remove_MyEvent(EventRegistrationToken registrationToken) { … }
It looks really great, allowing unsubscribing from event by “disposing” the registration token (Rx does the same kind of thing, returning IDisposable instance from Subscribe() method). So it’s became possible to easily unsubscribe lamba-expressions from events, but…
So how does C# allows for working with this kind of events? In .NET it’s possible to subscribe an method (static and instance) with one instance on delegate and unsubscribe with completely another delegate instance pointed to the same method. So if I using an WinRT event and just do unsubscribing of some delegate type instance in C#… where did compiler get the correct EventRegistrationToken? How all this magic works?
— update —
Actually EventRegistrationToken doesn’t allows to unsubscribe simply by calling some kind of Dispose() method, that is really sadly:
public struct EventRegistrationToken
{
internal ulong Value { get; }
internal EventRegistrationToken(ulong value)
public static bool operator ==(EventRegistrationToken left, EventRegistrationToken right)
public static bool operator !=(EventRegistrationToken left, EventRegistrationToken right)
public override bool Equals(object obj)
public override int GetHashCode()
}
— update2 —
WinRT interoperability actually uses global table of registration tokens when subscribing WinRT events with managed objets. For example, interop code for removing handlers looks like this:
internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
{
object target = removeMethod.Target;
var eventRegistrationTokenTable = WindowsRuntimeMarshal.ManagedEventRegistrationImpl.GetEventRegistrationTokenTable(target, removeMethod);
EventRegistrationToken obj2;
lock (eventRegistrationTokenTable)
{
List<EventRegistrationToken> list;
if (!eventRegistrationTokenTable.TryGetValue(handler, out list)) return;
if (list == null || list.Count == 0) return;
int index = list.Count - 1;
obj2 = list[index];
list.RemoveAt(index);
}
removeMethod(obj2);
}
That is really sadly.
When you add or remove a delegate to an WinRT event, like this:
It looks just like you were working with normal .Net events. But this code actually compiles to something like this (Reflector seems to have some trouble decompiling WinRT code, but I think this is what the code actually does):
This code won’t actually compile, because you can’t access the
add_andremove_methods from C#. But you can that in IL, and that’s exactly what the compiler does.It looks like
WindosRuntimeMarshalkeeps all thoseEventRegistrationTokens and uses them to unsubscribe when necessary.