只在基方法完成时调用派生方法
本文关键字:方法 调用 派生 完成时 | 更新日期: 2023-09-27 18:13:01
我觉得这是一个常见的场景,我很好奇是否有最佳实践解决方案。
像所有的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
代码。当然,我知道一些方法可以做到这一点:
-
SetProperty
可以返回一个bool,Derived
检查(看起来很丑,因为这个方法的其他1000个用户不关心返回值) - 重新检查
Derived
中的两个属性是否相等(简单,但不是DRY)
我总是喜欢保持DRY,我只是好奇是否有一个通用的解决方案,被认为是最佳实践?这似乎是整个框架中非常常见的场景。
看起来像偏执,但如果它如此重要,也许你应该尽量不要在这种情况下使用继承,并创建基类与验证(也许,也为两个ViewModelBases抽象超类)
您可以在新的派生类中添加一个委托方法到onpropertychange,当onpropertychange被触发时,它将在这个新方法中运行ValidateProperty方法调用到事件。所以你可以在派生方法中删除Validateproperty方法,并且你不需要新的override方法,因为你可以在属性更改时触发Validateproperty。
一种选择是使用第二个函数来指定更改属性时需要发生的操作。在基类中定义一个不做任何事情的虚方法,在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); });
}