Как события WinRT взаимодействуют с .NET

В последнем видео от команды Rx Барт Де Смет: Обновление Rx - .NET 4.5, Async, WinRT Я видел, что события WinRT открываются для .NET некоторыми действительно странными метаданными, точнее - add_ / remove_ сигнатура методов пары:

EventRegistrationToken add_MyEvent(EventHandler handler) { … }
void remove_MyEvent(EventRegistrationToken registrationToken) { … }

Похоже, действительно здорово, позволяя отказаться от подписки на событие путем «удаления» регистрационного токена (Rx делает то же самое, возвращая экземпляр IDisposable из метода Subscribe () ). Так что стало возможно легко отписывать лямба-выражения от событий, но ...

Так как же C # позволяет работать с такого рода событиями? В .NET можно подписать метод (статический и экземплярный) с одним экземпляром делегата и отказаться от подписки с полностью другим экземпляром делегата, указывающим на тот же метод. Итак, если я использую событие WinRT и просто отменяю подписку на какой-либо экземпляр типа делегата в C # ... где компилятор получил правильный EventRegistrationToken ? Как работает вся эта магия?

- update -

На самом деле EventRegistrationToken не позволяет отказаться от подписки, просто вызвав какой-то метод Dispose () , то есть действительно печально:

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 фактически использует глобальную таблицу токенов регистрации при подписке на события WinRT с управляемыми объектами. Например, код взаимодействия для удаления обработчиков выглядит так:

internal static void RemoveEventHandler(Action removeMethod, T handler)
{
  object target = removeMethod.Target;
  var eventRegistrationTokenTable = WindowsRuntimeMarshal.ManagedEventRegistrationImpl.GetEventRegistrationTokenTable(target, removeMethod);
  EventRegistrationToken obj2;
  lock (eventRegistrationTokenTable)
  {
    List 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);
}

Это действительно печально.

8
задан controlflow 15 October 2011 в 11:53
поделиться