Как события WinRT взаимодействуют с .NET - PullRequest
8 голосов
/ 15 октября 2011

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

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

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

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

- обновление -

На самом деле 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<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);
}

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

Ответы [ 2 ]

14 голосов
/ 15 октября 2011

Когда вы добавляете или удаляете делегата к событию WinRT, например:

this.Loaded += MainPage_Loaded;

this.Loaded -= MainPage_Loaded;

Выглядит так, как будто вы работали с обычными событиями .Net.Но этот код на самом деле компилируется примерно так (кажется, что Reflector имеет некоторые проблемы с декомпиляцией кода WinRT, но я думаю, что именно этот код и делает):

WindowsRuntimeMarshal.AddEventHandler<RoutedEventHandler>(
    new Func<RoutedEventHandler, EventRegistrationToken>(this.add_Loaded),
    new Action<EventRegistrationToken>(remove_Loaded),
    new RoutedEventHandler(this.MainPage_Loaded));

WindowsRuntimeMarshal.RemoveEventHandler<RoutedEventHandler>(
    new Action<EventRegistrationToken>(this.remove_Loaded),
    new RoutedEventHandler(this.MainPage_Loaded));

Этот код на самом деле не компилируется, потому чтоВы не можете получить доступ к add_ и remove_ методам из C #.Но вы можете сделать это в IL, и это именно то, что делает компилятор.

Похоже, WindosRuntimeMarshal сохраняет все эти EventRegistrationToken s и использует их для отмены подписки при необходимости.

9 голосов
/ 15 октября 2011

Примите ли вы в ответ «есть несколько удивительно умных людей, работающих над языковой проекцией C #»?

Если серьезно, то, что вы обнаружили, это низкоуровневая ABI (двоичная) реализация шаблона событий, языковая проекция C # знает этот шаблон и знает, как представить его как события C #. Внутри CLR есть классы, которые реализуют это отображение.

...