0

我希望将 cs-sdl 连接到 Rx。我已经让它在 C# 中工作,但在 F# 中开始发生一些相当奇怪的事情。我想坚持使用 F#,这样我可以节省一些编程时间并将 SDL 事件作为参数传递,以便将它们整齐地包装在 IObservables 中。这是我尝试这样做的方法:

let fromEvent (e: IEvent<'H,'T>) = Observable.FromEventPattern<'H,'T>((fun h -> e.AddHandler(h)),(fun h -> e.RemoveHandler(h)))

到目前为止一切都很好。现在将其中一个 SDL 事件传递给它并获得一个 IObservable...

let MouseMotion = fromEvent(Events.MouseMotion)

等等等等这组模块。所有推断的类型都是正确的。MouseMotion 是类型IObservable<MouseMotionEventArgs>

现在这是我在另一个项目中实际使用这个库的地方,我为它测试它:

let observer : IObserver<MouseMotionEventArgs> = Observer.Create(Action<MouseMotionEventArgs>(fun x -> System.Console.WriteLine(x.X.ToString())))
ignore <| SdlDotNet.Reactive.CoreInput.MouseMotion.Subscribe(Observer.AsObserver(observer))

这是我运行它时发生的情况:

  System.ArgumentException was unhandled
  Message="Type must derive from Delegate.\r\nParameter name: type"
  Source="mscorlib"
  ParamName="type"
  StackTrace:
       at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
       at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
       at System.Reactive.Linq.Observable.<>c__DisplayClass19d`2.<FromEvent>b__19b(IObserver`1 observer)
       at System.Reactive.AnonymousObservable`1.<>c__DisplayClass1.<Subscribe>b__0()
       at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
       at System.Reactive.Concurrency.ScheduledItem`2.InvokeCore()
       at System.Reactive.Concurrency.ScheduledItem`1.Invoke()
       at System.Reactive.Concurrency.CurrentThreadScheduler.Trampoline.Run()
       at System.Reactive.Concurrency.CurrentThreadScheduler.Schedule[TState](TState state, TimeSpan dueTime, Func`3 action)
       at System.Reactive.Concurrency.CurrentThreadScheduler.Schedule[TState](TState state, Func`3 action)
       at System.Reactive.Concurrency.Scheduler.Schedule(IScheduler scheduler, Action action)
       at System.Reactive.AnonymousObservable`1.Subscribe(IObserver`1 observer)
       at <StartupCode$SdlDemo>.$Tutorial.main@() in C:\Users\Barend Venter\Documents\Visual Studio 2008\Projects\SdlDemo\SdlDemo\Tutorial.fs:line 77
  InnerException: 

我完全被难住了。为什么会这样?我需要在某个地方做一些 eta 扩展吗?

4

3 回答 3

1

经过一番摆弄,我能够将运行时异常变成一个方便的类型错误。似乎将观察者的类型从 更改为IObserver<MouseMotionEventArgs>IObserver<EventPattern<MouseMotionEventArgs>>这里可以解决问题:

let observer = Observer.Create(fun (x : EventPattern<MouseMotionEventArgs>) -> System.Console.WriteLine(x.EventArgs.X.ToString()))
ignore <| SdlDotNet.Reactive.CoreInput.MouseMotion.Subscribe((observer))

不幸的是,在我发布了几天后,我很快就找到了一个解决方案。希望它对某人有用。

于 2012-08-22T10:10:24.653 回答
1

与其创建自己的包装函数来使 F# 适应 Rx,为什么不直接使用标准 F#Control.Observable模块中的函数呢?

于 2012-08-22T12:39:49.713 回答
1

这可能无法解决您的其余问题,但是您是否注意到IEvent 继承自 IObservable?您的fromEvent功能可以实现为一个简单的演员...

let fromEvent (e: IEvent<'H,'T>) = e :> IObservable<'T>
于 2012-08-24T19:16:02.960 回答