WinRT事件如何与.NET互操作 [英] How WinRT events are interoperate with .NET

查看:124
本文介绍了WinRT事件如何与.NET互操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

=nofollow> Bart De Smet:Rx Update - .NET 4.5,Async,WinRT 我看到WinRT事件暴露给.NET,有一些非常奇怪的元数据,更精准 - add _ / remove _ pair methods signature:

 code> EventRegistrationToken add_MyEvent(EventHandler< MyEventArgs>处理程序){...} 
void remove_MyEvent(EventRegistrationToken registrationToken){...}

看起来真的很棒,允许通过处理注册令牌取消订阅事件(Rx做同样的事情,返回 IDisposable 实例从 Subscribe()方法)。所以可以轻松地从事件中取消订阅Lamba表达式,但... ...



那么C#如何允许使用这种事件呢?在.NET中,可以使用一个实例在委托上订阅一个方法(静态和实例),并使用指向同一方法的完全另一个委托实例取消订阅。所以如果我使用WinRT事件,并且只是在C#中取消订阅一些委托类型的实例...编译器在哪里可以获得正确的 EventRegistrationToken ?所有这些魔法都有效?



- 更新 -



code> EventRegistrationToken 不允许简单地通过调用某种 Dispose()方法来取消订阅,这真的是令人遗憾的: p>

  public struct EventRegistrationToken 
{
internal ulong Value {get;
内部EventRegistrationToken(ulong值)
public static bool operator ==(EventRegistrationToken left,EventRegistrationToken right)
public static bool operator!=(EventRegistrationToken left,EventRegistrationToken right)
public覆盖bool Equals(object obj)
public override int GetHashCode()
}

- update2 -



WinRT互操作性实际上使用注册令牌的表格,在使用管理的订阅WinRT事件时OBJETS。例如,用于删除处理程序的互操作代码如下所示:

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

真的很伤心。

解决方案

当您添加或删除WinRT事件的代理时,如下所示:

  this.Loaded + = MainPage_Loaded; 

this.Loaded - = MainPage_Loaded;

看起来就像您正在使用正常的.Net事件。但是这个代码实际上是编译成这样的东西(反射器似乎有一些问题反编译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));

此代码实际上不会编译,因为您无法访问从C#中添加_ remove _ 方法。但是你可以在IL中,这正是编译器所做的。



它看起来像 WindosRuntimeMarshal 保留所有这些 EventRegistrationToken ,并在必要时使用它们取消订阅。


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:

this.Loaded += MainPage_Loaded;

this.Loaded -= MainPage_Loaded;

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):

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));

This code won't actually compile, because you can't access the add_ and remove_ methods from C#. But you can that in IL, and that's exactly what the compiler does.

It looks like WindosRuntimeMarshal keeps all those EventRegistrationTokens and uses them to unsubscribe when necessary.

这篇关于WinRT事件如何与.NET互操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆