我有一个 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)
我该如何执行以下任一操作来解决该问题?
- 修改 COM 库以修复非标准事件类型错误。
- 在 Observer.take/Observer.subscribe 中使用显式 add_/remove_ 函数。
- 在取消订阅之前触发事件 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/