IObservable.Subscribe导致System.Delegate.CreateDelegate抛出ArgumentException

时间:2012-08-22 09:53:39

标签: .net f# sdl system.reactive

我希望将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扩展吗?

3 个答案:

答案 0 :(得分: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))

或许不幸的是,在我发布这里之后很快就会找到一个让我好几天的解决方案。希望它对某人有用。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

这可能无法解决您的其他问题,但您是否注意到IEvent inherits from IObservable?您的fromEvent函数可以实现为简单的演员......

let fromEvent (e: IEvent<'H,'T>) = e :> IObservable<'T>