events - F# 响应式(Reactive)订阅来自 COM 的非标准事件

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

我有一个 native COM 库(我可以对其进行修改),并且有一个 F# 应用程序尝试通过 Rx 使用项目中引用的 Interop 库中的事件。

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

这里的错误消息,我不完全理解,是:

The event 'ComEventArrived' has a non-standard type. If this event is declared in another CLI language, you may need to access this event using the explicit add_ComEventArrived and remove_ComEventArrived methods for the event. If this event is declared in F#, make the type of the event an instantiation of either 'IDelegateEvent<>' or 'IEvent<,_>'.

我不介意使用 add_ComEventArrived 但我不知道如何使用 Observable

奇怪的是,ComEventArrived 有 2 个内部互操作类型的参数,如果我尝试订阅仅编码(marshal) 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 中使用显式 add_/remove_ 函数。
  3. 在取消订阅之前触发事件 n 次而不使用可变/锁的其他方式。

到目前为止我已阅读:

最佳答案

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

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

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,所以我不怀疑您会需要这样的东西)。

关于events - F# 响应式(Reactive)订阅来自 COM 的非标准事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43517562/

相关文章:

javascript - 为什么我的参数没有传递到已调度的事件?

Java SWT 创建监听器来更改标签文本并返回数据

f# - 在 F# 中,如何生成具有 Func<obj> 类型的表达式?

f# - 在 .net 5 中运行 Forms 表单 F# 脚本?

c# - 如何响应 ContextMenuStrip 项单击

c# - 我应该使用 EventArgs 还是简单的数据类型?

casting - F# 类型转换运算符

c# - 使用 COM 对 C# 应用程序进行内存分析

windows - 当一个类由于某种设计原因没有实现方法时返回哪个 HRESULT?

c++ - COM 进程内 DLL 中的 DllMain 问题