我有一个本机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)
如何解决此问题?
到目前为止我已阅读:
答案 0 :(得分:2)
我不知道具体的COM互操作,但我可以举一个将非标准事件转换为IObservable
的例子,这应该涵盖你的第二点。
非标准事件的一个示例是AppDomain.CurrentDomain.AssemblyResolve
,其中事件处理程序需要返回Assembly
而不是返回unit
。要使用IObservable
和add_
函数将其封装到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
,所以我不怀疑你需要这样的东西。)