Наблюдаемая логика - это случай наследования классов - PullRequest
0 голосов
/ 12 декабря 2018

Как правильно написать сложную наблюдаемую логику в случае наследования классов?

Пожалуйста, проверьте пример:

    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 свойств в каждом классе, чтобы наблюдать ... сложные логические решения)

PS понятия не имею, что добавить к моему вопросу «в основном кода».Надеюсь, что вы найдете "более подробную информацию" в комментариях к коду.

1 Ответ

0 голосов
/ 12 декабря 2018

Проблема в том, что вы вызываете виртуальный метод в своем конструкторе (даже если он встроен в ваш WhenAnyValue вызов).

Лучше всего перейти на виртуальный Initialize () вызов метода, чтобы вы могли сначала создать BProperty , а затем вызвать базукласса, или перейдите на композиционный дизайн, где ваша логика BProperty размещена в другом месте.

Проблема с виртуальными методами в конструкторах заключается в том, что вы не можете контролировать, когда вызывается конструктор базового класса,он всегда вызывается перед вашим конструктором производных классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...