Kla*_*sen 16 .net c# oop generics
假设我们的系统可以执行操作,并且操作需要一些参数来完成其工作.我为所有操作定义了以下基类(简化了您的阅读乐趣):
public abstract class BaseBusinessAction<TActionParameters>
: where TActionParameters : IActionParameters
{
protected BaseBusinessAction(TActionParameters actionParameters)
{
if (actionParameters == null)
throw new ArgumentNullException("actionParameters");
this.Parameters = actionParameters;
if (!ParametersAreValid())
throw new ArgumentException("Valid parameters must be supplied", "actionParameters");
}
protected TActionParameters Parameters { get; private set; }
protected abstract bool ParametersAreValid();
public void CommonMethod() { ... }
}
Run Code Online (Sandbox Code Playgroud)
只有具体实现BaseBusinessAction知道如何验证传递给它的参数是否有效,因此它
ParametersAreValid是一个抽象函数.但是,我希望基类构造函数强制传递的参数始终有效,所以我添加了ParametersAreValid对构造函数的调用,并在函数返回时抛出异常false.到目前为止一切都那么好吧?好吧,不.代码分析告诉我" 不要在构造函数中调用可覆盖的方法 "这实际上很有意义,因为当调用基类的构造函数时,子类的构造函数尚未被调用,因此该ParametersAreValid方法可能无法访问某些关键子类的构造函数将设置的成员变量.
所以问题是:我如何改进这个设计?
我是否Func<bool, TActionParameters>向基类构造函数添加了一个参数?如果我做了:
public class MyAction<MyParameters>
{
public MyAction(MyParameters actionParameters, bool something) : base(actionParameters, ValidateIt)
{
this.something = something;
}
private bool something;
public static bool ValidateIt()
{
return something;
}
}
Run Code Online (Sandbox Code Playgroud)
这会起作用,因为它ValidateIt是静态的,但我不知道......有更好的方法吗?
评论非常欢迎.
这是继承层次结构中的常见设计挑战 - 如何在构造函数中执行依赖于类的行为.代码分析工具将此标记为问题的原因是派生类的构造函数尚未有机会在此时运行,并且对虚方法的调用可能取决于尚未初始化的状态.
所以你有几个选择:
如果可能,让每个构造函数执行验证.但这并不总是令人满意的.在这种情况下,我个人更喜欢工厂模式,因为它使实现保持直接,并且它还提供了一个拦截点,可以在以后添加其他行为(日志记录,缓存等).但是,有时工厂没有意义,在这种情况下,我会认真考虑创建一个独立验证器类型的第四个选项.
这是代码示例:
public interface IParamValidator<TParams>
where TParams : IActionParameters
{
bool ValidateParameters( TParams parameters );
}
public abstract class BaseBusinessAction<TActionParameters,TParamValidator>
where TActionParameters : IActionParameters
where TParamValidator : IParamValidator<TActionParameters>, new()
{
protected BaseBusinessAction(TActionParameters actionParameters)
{
if (actionParameters == null)
throw new ArgumentNullException("actionParameters");
// delegate detailed validation to the supplied IParamValidator
var paramValidator = new TParamValidator();
// you may want to implement the throw inside the Validator
// so additional detail can be added...
if( !paramValidator.ValidateParameters( actionParameters ) )
throw new ArgumentException("Valid parameters must be supplied", "actionParameters");
this.Parameters = actionParameters;
}
}
public class MyAction : BaseBusinessAction<MyActionParams,MyActionValidator>
{
// nested validator class
private class MyActionValidator : IParamValidator<MyActionParams>
{
public MyActionValidator() {} // default constructor
// implement appropriate validation logic
public bool ValidateParameters( MyActionParams params ) { return true; /*...*/ }
}
}
Run Code Online (Sandbox Code Playgroud)
如果您仍然推迟使用子类来验证参数,为什么不在子类构造函数中简单地执行此操作?我理解您正在努力的原则,即强制执行从您的基类派生的任何类验证其参数.但即便如此,基类的用户可以简单地实现一个ParametersAreValid()只返回true 的版本,在这种情况下,该类遵守合同的字母,而不是精神.
对我来说,我通常会在调用任何方法的开头进行这种验证.例如,
public MyAction(MyParameters actionParameters, bool something)
: base(actionParameters)
{
#region Pre-Conditions
if (actionParameters == null) throw new ArgumentNullException();
// Perform additional validation here...
#endregion Pre-Conditions
this.something = something;
}
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助.
| 归档时间: |
|
| 查看次数: |
473 次 |
| 最近记录: |