Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WinRT事件如何与.NET互操作_C#_Events_Event Handling_System.reactive_Windows Runtime - Fatal编程技术网

C# WinRT事件如何与.NET互操作

C# WinRT事件如何与.NET互操作,c#,events,event-handling,system.reactive,windows-runtime,C#,Events,Event Handling,System.reactive,Windows Runtime,在Rx团队的最新视频中,我看到WinRT事件通过一些非常奇怪的元数据暴露到.NET中,更准确地说-add/remove配对方法签名: EventRegistrationToken add_MyEvent(EventHandler<MyEventArgs> handler) { … } void remove_MyEvent(EventRegistrationToken registrationToken) { … } --更新2-- WinRT互操作性实际上在使用托管对象订阅Win

在Rx团队的最新视频中,我看到WinRT事件通过一些非常奇怪的元数据暴露到.NET中,更准确地说-
add
/
remove
配对方法签名:

EventRegistrationToken add_MyEvent(EventHandler<MyEventArgs> handler) { … }
void remove_MyEvent(EventRegistrationToken registrationToken) { … }
--更新2--

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);
}
this.Loaded += MainPage_Loaded;

this.Loaded -= MainPage_Loaded;
内部静态void removeventhandler(Action removethod,T handler)
{
对象目标=removeMethod.target;
var eventRegistrationTokenTable=WindowsRuntimeMarshal.ManagedEventRegistrationImpl.GetEventRegistrationTokenTable(目标,removeMethod);
事件注册令牌obj2;
锁(eventRegistrationTokenTable)
{
名单;
if(!eventRegistrationTokenTable.TryGetValue(处理程序,输出列表))返回;
if(list==null | | list.Count==0)返回;
int index=list.Count-1;
obj2=列表[索引];
列表。删除(索引);
}
去除法(obj2);
}

这真的很遗憾。

当您添加或删除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);
}
this.Loaded += MainPage_Loaded;

this.Loaded -= MainPage_Loaded;
看起来就像是在处理正常的.Net事件。但是这段代码实际上编译成了这样的东西(Reflector似乎在反编译WinRT代码时遇到了一些问题,但我认为这就是代码的实际用途):

WindowsRuntimeMarshal.AddEventHandler(
新函数(已加载此.add_),
新动作(移除已加载的单元),
新RoutedEventHandler(此.MainPage_已加载));
WindowsRuntimeMarshal.RemoveEventHandler(
新操作(此。移除加载的_),
新RoutedEventHandler(此.MainPage_已加载));
这段代码实际上不会编译,因为您无法从C#访问
add_
remove_
方法。但是你可以在IL中找到它,而这正是编译器所做的

它似乎保留了所有这些
EventRegistrationToken
s,并在必要时使用它们来取消订阅。

您是否接受“有一些非常聪明的人在处理C语言投影”作为答案


更严重的是,您发现的是事件模式的低级ABI(二进制)实现,C#language投影知道这种模式,并且知道如何将其作为C#事件公开。CLR中有一些类实现了这种映射。

哦,不,似乎它确实保留了托管对象所有订阅的全局表……MSDN在上有一篇关于这方面的非常好的文章@斯维克,你不是那么远,听起来更像是C.W.WrRT团队给猪涂口红:为什么在猪身上涂口红?这正是语言投射的工作原理。windows运行时具有事件模式(以及异步模式、集合模式和其他模式)。每个公开事件的API都使用相同的模式。语言投影的工作是获取使用该模式的API,并使其对该语言的用户感到自然和熟悉。windows运行时不能简单地采用C#事件模式,因为有两个原因:windows运行时必须是语言无关的,并且运行时使用引用计数进行生存期管理。不幸的是,这也是正确的。事件的低级投影很简单-有一个事件添加和一个事件移除方法,add接受一个委托并返回一个令牌,remove接受令牌。触发事件时,将调用委托。CLR将此低级机制映射到与CLR兼容的版本。使用的类的实际名称是一个实现细节,在不同的构建中可能会发生更改。JavaScript与C++一样有完全不同的实现机制。所有的实现都可能发生变化。请注意,您描述的所有内容都是实现细节,可能随时会发生变化。你永远不应该依赖你逆向工程的任何行为。