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

问题描述 投票:0回答:3

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

消息是“对象或值的初始化导致对象或值在完全初始化之前被递归访问”,它发生在读取传递给

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
中,
kicker
fillInValue
的组合导致在通过
PropertyChanged

通知任何更改之前查询值
.net f# reactiveui
3个回答
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 @>)

2
投票

嗯,虽然我不是 F# 专家,但您可能不得不避开 ToProperty(它实际上只是一个助手)并使用读/写属性(即通过

RaiseAndSetIfChanged
构建的属性)和简单的
Subscribe
+ 属性赋值.如此易变和恶心!

ReactiveUI 非常喜欢在构造函数中初始化属性,因为它设置了应用程序的初始状态(如果你使用

ObservableForProperty
,你会发现你必须一直使用
.StartWith
运算符,否则事情就赢了在第一次更改之前一直工作)


0
投票

ToProperty
调用
deferSubscription = true
也解决了这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.