我正在尝试复制一些从IObservable
事件创建Button.Click
的C#代码。
我想将此代码移植到F#。
这是原始的C#代码,它编译时没有错误:
Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => btn.Click += h,
h => btn.Click -= h))
这是我在F#中尝试做同样的失败:
Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
Func<EventHandler<RoutedEventArgs>, RoutedEventHandler>(fun h -> RoutedEventHandler(h)),
Action<RoutedEventHandler>(fun h -> btn.Click.AddHandler h),
Action<RoutedEventHandler>(fun h -> btn.Click.RemoveHandler h))
除了声明的第二行,一切都很愉快。
F#编译器抱怨fun h -> RoutedEventHandler(h)
因为
除h
作为RoutedEventHandler
构造函数的参数外,它不希望这样做。
另一方面,C#编译器似乎没有接受h => new RoutedEventHandler(h)
有趣的是,在两个代码示例(C#和F#)中,h
的类型为EventHandler<RoutedEventArgs>
。
我从F#编译器获取的错误消息是:
错误2此表达式的类型为obj - &gt; RoutedEventArgs - &gt;单位,但这里有类型EventHandler
我在PresentationCore中找到的RoutedEventHandler
签名是:
public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
正如您所看到的,它确实需要object
和RoutedEventArgs
作为参数,因此F#编译器实际上是正确的。
C#编译器在幕后做了一些神奇的工作来使F#编译器不能正常工作,或者我只是在这里遗漏了什么?
无论哪种方式,我怎样才能在F#中完成这项工作?
答案 0 :(得分:17)
我知道从WPF Button.Click事件中制作IObservable<_>
的最简单方法是投射它:
open System
open System.Windows.Controls
let btn = new Button()
let obsClick = btn.Click :> IObservable<_>
检查obsClick ...
val obsClick : IObservable<Windows.RoutedEventArgs>
这是可能的,因为标准.NET事件的F#表示是类型(在本例中)IEvent<Windows.RoutedEventHandler,Windows.RoutedEventArgs>
。正如您在文档中看到的那样,IEvent implements IObservable。换句话说,在F#中,每个单独的事件都是IObservable
。
答案 1 :(得分:6)
乔尔·穆勒(Joel Mueller)很受欢迎,所以只是为了记录:C#代码的直接翻译将是
Observable.FromEvent(
(fun h -> RoutedEventHandler(fun sender e -> h.Invoke(sender, e))),
(fun h -> b.Click.AddHandler h),
(fun h -> b.Click.RemoveHandler h)
)