C# 可观察逻辑是类继承的例子

C# 可观察逻辑是类继承的例子,c#,system.reactive,reactiveui,C#,System.reactive,Reactiveui,在类继承的情况下,如何正确地编写复杂的可观察逻辑 请检查一个示例: public class A : ReactiveObject { public A() { AProperty = new SimpleValue(); this.WhenAnyValue(x => x.AProperty) // virtual method call in constructor .Subscri

在类继承的情况下,如何正确地编写复杂的可观察逻辑

请检查一个示例:

    public class A : ReactiveObject
{
    public A()
    {
        AProperty = new SimpleValue();

        this.WhenAnyValue(x => x.AProperty)
            // virtual method call in constructor
            .Subscribe(x => CheckIsChanged());

        // this will crash app because B is not initialized
        AProperty.Value = true;
    }

    #region "AProperty" property

    private SimpleValue _aProperty;

    public SimpleValue AProperty
    {
        get { return _aProperty; }
        set { this.RaiseAndSetIfChanged(ref _aProperty, value); }
    }

    #endregion

    protected virtual bool CalculateIsChanged()
    {
        return AProperty.Value;
    }

    protected void CheckIsChanged()
    {
        IsChanged = CalculateIsChanged();
    }

    #region "IsChanged" property

    private bool _isChanged;

    public bool IsChanged
    {
        get { return _isChanged; }
        set { this.RaiseAndSetIfChanged(ref _isChanged, value); }
    }

    #endregion
}

public class B : A
{
    public B()
    {
        BProperty = new SimpleValue();
    }

    protected override bool CalculateIsChanged()
    {
        // crash will happen here
        return BProperty.Value || base.CalculateIsChanged();

        // definitely we can check BProperty for null
        // but i hope there are more elegant way to do not call such methods before all class tree initialized
        // or better way to write everything :)
    }

    #region "BProperty" property

    private SimpleValue _bProperty;

    public SimpleValue BProperty
    {
        get { return _bProperty; }
        set { this.RaiseAndSetIfChanged(ref _bProperty, value); }
    }

    #endregion
}

public class SimpleValue: ReactiveObject
{
    #region "Value" property

    private bool _value;

    public bool Value
    {
        get { return _value; }
        set { this.RaiseAndSetIfChanged(ref _value, value); }
    }

    #endregion
}
这是一个简单的示例,但上的依赖项和逻辑可能要困难得多(每个类中有10个属性需要观察…复杂的逻辑决策)


旁白:我不知道我的“主要是代码”问题需要补充什么。希望您能在代码注释中找到“更多详细信息”。

问题在于您在构造函数中调用了一个虚拟方法(即使它嵌入在WhenyValue调用中)

最好的选择是转到虚拟初始化()方法调用,这样您可以先创建BProperty,然后再调用基类,或者转到基于组合的设计,其中BProperty逻辑位于其他位置


构造函数中的虚拟方法的问题是,您无法控制何时调用基类的构造函数,它总是在派生类构造函数之前被调用。

谢谢,但这是一个难题(临时解决方案(如果我在构造函数中删除属性赋值或添加另一个属性赋值…)您的问题的一部分是您依赖构造函数中的虚拟方法,这是一个很大的问题。人们通常通过在类中使用Initialize()方法来解决这个问题。在这种情况下,构造函数的调用顺序与您希望的相反。而且我认为您的解决方案迫切需要在这种情况下进行组合。如果你有一个带有派生功能的构造函数注入对象,它可能会允许一些解耦。感谢Glenn的评论。1.这是理解问题的最简单的例子。2.构造函数中没有直接调用虚拟方法(我知道这很糟糕)。3.我要求更好的解决方案,而你目前的建议是多次“跳过”处理事件。4.如果您有另一种“大是是”的方法来分解不同类中的逻辑,那么您总是受欢迎的。CalculatesChanged在构造函数中由WhenyValue调用,该调用是虚拟的,用于解决您的问题。因此建议将其移动到initialize方法中。由于打破了在构造函数中调用虚拟方法的一般建议,您的BProperty将不存在。