为什么ObservableForProperty上的ReactiveUI的ToProperty导致F#中的FailInit

时间:2013-11-13 15:58:26

标签: .net f# reactiveui

在ReactiveUI 5.2.0和F#3.1中,以下F#代码在构造对象时会导致InvalidOperationException(来自C#WPF应用程序)

消息是“对象或值的初始化导致在完全初始化之前递归访问对象或值”并且在读取传递到ObservableForProperty的属性期间发生(尽管默认为跳过初始值。)

type MyVM() as this =
inherit ReactiveObject()

let source : obj = obj()

let ofp =            
    this.ObservableForProperty([|"Source"|])
         .Select(fun x -> x.Value)
        .ToProperty(this, (fun y -> y.Result), obj()) // Exception when executing this

member this.Result with get() = ofp.Value
member this.Source with get() = source // Exception here "The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized"

编辑添加: 问题似乎是ToProperty导致ObservableForProperty在订阅时查询“Source”属性,并且F#检查构造函数在查询属性之前已完成。

更多信息:ReactiveNotifyPropertyChangedMixin.nestedObservedChanges中,kickerfillInValue的组合会导致在通过PropertyChanged

通知任何更改之前查询该值

2 个答案:

答案 0 :(得分:3)

从ReactiveUI版本5.4.0开始,ObservableForProperty有一个新的重载,需要一个简单的非链式属性来监控。

如果您添加以下扩展方法:

let toPropName(query : Expr) = 
    match query with
        | PropertyGet(a, b, list) -> b.Name
        | _ -> ""

[<Extension>]
type ReactiveObjectExtender =
    [<Extension>]
    static member ObservableForProperty<'u, 't when 'u :> ReactiveObject>(this: 'u, expr : Expr<'t>, ?beforeChange, ?skipInitial) =
        let propertyName = toPropName expr
        this.ObservableForProperty<'u, 't>(propertyName, defaultArg beforeChange false, defaultArg skipInitial true)

然后您可以使用以下语法观察属性更改:

this.ObservableForProperty(<@ this.MyProperty @>)

答案 1 :(得分:2)

嗯,虽然我不是F#专家,你可能不得不避开ToProperty(它实际上只是一个助手)并使用读/写属性(即通过RaiseAndSetIfChanged构建的属性)和一个简单的{{ 1}} +属性赋值。所以可变和总体!

ReactiveUI非常喜欢在构造函数中初始化属性,因为它设置了应用程序的初始状态(如果使用Subscribe,您会发现必须使用ObservableForProperty运算符时间或其他事情在第一次改变之前不会起作用)