仅在基本方法完成时调用派生方法

时间:2015-09-16 21:09:49

标签: c# wpf inheritance override dry

我觉得这是一种常见的情况,如果有最佳实践解决方案,我很好奇。

与所有WPF一样,我在ViewModelBase上设置了一个设置属性值并调用OnPropertyChanged的方法:

protected virtual void SetProperty<T>(string propertyName, ref T oldValue, T newValue)
{
    if (Equals(oldValue, newValue)) return;

    oldValue = newValue;
    OnPropertyChanged(propertyName);
}

我有一个派生类SaveableViewModelBase执行一些错误检查和其他事情,它会覆盖SetProperty

protected override void SetProperty<T>(string propertyName, ref T oldValue, T newValue)
{
    base.SetProperty(propertyName, ref oldValue, newValue);
    ValidateProperty(propertyName, newValue);
}

我的问题是,如果Base过早返回,因为项目相同,我不想调用我的Derived代码。当然,我知道有几种方法可以做到这一点:

  1. SetProperty可以返回Derived检查的bool(看起来很难看,因为此方法的其他1000个用户不关心返回值)
  2. 重新检查Derived中的两个属性是否相等(简单,但不是DRY)
  3. 我总是喜欢保持干燥,我很好奇是否有一个常见的解决方案来解决这个被认为是最佳做法的问题?在整个框架中,它似乎是一个非常常见的场景。

3 个答案:

答案 0 :(得分:0)

看起来像偏执狂,但如果它如此重要,也许你会尝试在这种情况下不使用继承并创建带有验证的Base类(也许,也可能是两个ViewModelBases的抽象超类)

答案 1 :(得分:0)

您可以在新派生类中为onpropertychange添加委托方法,并且当触发onpropertychange时,它将在调用此事件的新方法中运行ValidateProperty方法。因此,您可以在派生方法中删除Validateproperty方法,并且您不需要新的覆盖方法,因为您可以在属性更改时触发Validateproperty。

答案 2 :(得分:0)

一种选择是使用第二个函数来指定更改属性时需要执行的操作。在基础中定义一个不执行任何操作的虚方法,在SetProperty内调用该方法,然后覆盖子类中的虚方法。

在基类中,你会这样做:

protected virtual void SetProperty<T>(string propertyName, ref T oldValue, T newValue)
{
    if (Equals(oldValue, newValue)) return;

    oldValue = newValue;
    // Validate the property that was just changed.
    PropertyValidate(propertyName, ref oldValue, newValue);
    OnPropertyChanged(propertyName);
}

protected virtual void PropertyValidate<T>(string propertyName, ref T oldValue, T newValue)
{}

在子类中:

protected override void PropertyValidate<T>(string propertyName, ref T oldValue, T newValue)
{
    // Do some validation, adding some red marks to bad things.
}

另一个解决方案(我首先想到的过于复杂的解决方案)是回调。您可以为SetProperty<T>提供Action参数,并将重写SetProperty<T>添加到Action的验证中。类似的东西:

protected virtual void SetProperty<T>(
    string propertyName,
    ref T oldValue,
    T newValue,
    Action onChanged = null)
{
    if (Equals(oldValue, newValue)) return;

    oldValue = newValue;
    onChanged?.Invoke(); // Invoke the onChanged action (if not null).
    OnPropertyChanged(propertyName);
}

protected override void SetProperty<T>(
    string propertyName,
    ref T oldValue,
    T newValue,
    Action onChanged = null)
{
    // Wrap the given onChanged callback with a new one that also validates the property.
    base.SetProperty(propertyName, ref oldValue, newValue,
        () => { onChanged?.Invoke(); ValidateProperty(propertyName, newValue); });
}