可观察的逻辑是类继承的情况

时间:2018-12-12 02:43:34

标签: c# system.reactive reactiveui

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

请检查示例:

    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个属性可以观察...复杂的逻辑决策)

P.S。不知道要添加什么到我的“主要是代码”问题中。希望您在代码注释中找到“更多详细信息”。

1 个答案:

答案 0 :(得分:1)

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

您最好的选择是转到虚拟 Initialize()方法调用,这样您可以先创建 BProperty 然后调用基类,或者转到基于合成的设计,其中您的 BProperty 逻辑将托管在其他位置。

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