F#Reactive订阅来自COM的非标准事件

时间:2017-04-20 10:56:15

标签: events f# com system.reactive com-interop

我有一个本机COM库(我可以修改),并且我有一个F#应用程序尝试使用来自项目中引用的Interop库的Rx来使用事件。

let events = obj :?> _IInteropEvents_Event
let disposable = 
    Observable.take 1 events.ComEventArrived
    |> Observable.subscribe (fun sender data -> ()) // sender : ISender, data : IData

此处的错误消息,我不完全理解,是:

  

活动' ComEventArrived'有一个非标准的类型。如果这个事件是   用另一种CLI语言声明,您可能需要访问此事件   使用显式的add_ComEventArrived和remove_ComEventArrived   事件的方法。如果在F#中声明此事件,请创建类型   事件的实例化' IDelegateEvent< >'要么   '&IEvent LT; ,_>'

我不介意使用add_ComEventArrived,但我无法弄清楚如何使用Observable

奇怪的是,ComEventArrived有2个内部互操作类型的参数,如果我尝试订阅其他简单编组IUnknown的事件,它就可以工作,而且我没有"非标准类型"错误:

let events = obj :?> _ISnapshotEvents_Event
let disposable = 
    Observable.take 1 events.SnapshotEventArrived
    |> Observable.subscribe (fun sender -> ()) // sender : IUnknown (unit)

如何解决此问题?

  1. 修改COM库以修复非标准事件类型错误。
  2. 在Observer.take / Observer.subscribe。
  3. 中使用显式的add_ / remove_函数
  4. 在取消订阅之前触发事件的其他方式 n ,而不使用mutable / lock。
  5. 到目前为止我已阅读:

1 个答案:

答案 0 :(得分:2)

我不知道具体的COM互操作,但我可以举一个将非标准事件转换为IObservable的例子,这应该涵盖你的第二点。

非标准事件的一个示例是AppDomain.CurrentDomain.AssemblyResolve,其中事件处理程序需要返回Assembly而不是返回unit。要使用IObservableadd_函数将其封装到remove_,您可以写:

let assemblyResolve = 
  { new IObservable<_> with
      member x.Subscribe(observer) =
        let handler = ResolveEventHandler(fun o a -> 
          let mutable res = None 
          observer.OnNext((o, a, fun a -> res <- Some a))
          res.Value )
        AppDomain.CurrentDomain.add_AssemblyResolve(handler)
        { new IDisposable with
            member x.Dispose() = 
              AppDomain.CurrentDomain.remove_AssemblyResolve(handler) } }

我们使用F#对象表达式创建IObservable的新实现。在Subscribe成员中,我们创建了ResolveEventHandler并使用add_AssemblyResolve添加它。 Subscribe的结果是IDisposable实现,然后使用remove_AssemblyResolve取消注册事件处理程序。

这里丑陋的黑客是观察者的OnNext函数不能返回任何东西,所以我们给它一个带有参数的三元素元组,还有一个设置返回值的函数(这是特定于AssemblyResolve,所以我不怀疑你需要这样的东西。)

相关问题