3

在 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在订阅时查询“源”属性,并且 F# 在查询属性之前检查构造函数是否已完成。

更多信息: 在中,和ReactiveNotifyPropertyChangedMixin.nestedObservedChanges的组合导致在通过通知任何更改之前查询值kickerfillInValuePropertyChanged

4

2 回答 2

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 @>)
于 2013-12-16T16:07:22.283 回答
2

嗯,虽然我不是 F# 专家,但您可能不得不避开 ToProperty(它实际上只是一个助手)并使用一个读/写属性(即通过 构造的一个RaiseAndSetIfChanged)和一个简单的Subscribe+ 属性分配。如此多变和恶心!

ReactiveUI 真的很喜欢在构造函数中初始化属性,因为它设置了应用程序的初始状态(如果你使用ObservableForProperty,你会发现你必须一直使用.StartWith操作符,否则事情直到第一次才会起作用他们改变了)

于 2013-11-14T18:23:15.653 回答