我有一个关于C#和继承的简单基本问题。
在下面的例子中,我展示了两种设置必须设置属性的方法(CaptionDisplayText和Firstname):
public abstract class BaseClass
{
private string _firstName;
protected BaseClass(string captionDisplayText)
{
this.CaptionDisplayText = captionDisplayText;
this._firstName = this.GetFirstName();
}
protected string CaptionDisplayText { get; private set; }
protected abstract string GetFirstName();
}
public class DerivedClass : BaseClass
{
protected DerivedClass():base(String.Empty)
{
}
protected override string GetFirstName()
{
return String.Empty;
}
}
方法1,CaptionDisplayText,引入一个属性并在构造函数中设置它,而方法2引入了一个在Derived类中重写的抽象方法。
我知道如果方法是虚拟的而不是抽象的,Approach2是坏的,但是这里它是抽象的,这意味着它在基类的构造函数之前执行,并且没问题。
我有10-15个属性/字段,必须由我的派生类设置,所以我在想哪种方法更易于维护,可读和可测试。
我认为方法1更容易测试,而方法2更具可读性。方法2也是可测试的,因为模拟对象无论如何都必须实现抽象成员。
您认为哪种方式最好,还有第三种方法吗?
非常感谢,
答案 0 :(得分:0)
您是否考虑过使用CodeContracts和ClassInvariant?
答案 1 :(得分:0)
如果你想让类可测试,那么在构造函数中执行逻辑是不可取的。所以通过这样做._firstName = this.GetFirstName();将引入额外的测试工作,即使您不想对名字做任何事情,也会调用代码。在第一种方法中,您可以使用null填充它,这表示它对您的测试并不重要。
答案 2 :(得分:0)
通过我,最好的是第一个,因为它明确地设置数据并向调用者提供在构造对象期间必须设置的强制信息。
这里唯一可以遇到的“问题”是一定数量的属性,此时就像ctor中的参数一样,这在一个方法中看到了15个参数。但可能是这可以通过ctor重载“避免”(很难知道我不知道你的应用程序),如果你从某些属性值设置可以扣除其他属性“默认”值。
还有一个词典/ HashSet或任何解决方案,但对我来说,这个解决方案也很奇怪。
希望这有帮助。
问候。
答案 3 :(得分:0)
对我而言,这看起来令人困惑。为什么使用GetFirstName设置名字。作为抽象的SetFirstName方法执行此操作并在其中执行逻辑而不是将其隐藏在构造函数中是不是更好?我同意这是一个棘手/好的方式,但可能会让一些人感到困惑。在实现GetFirstName方法的派生类中,您要在基类中设置它是不直观的。
像保护抽象字符串SetFirstName();这样,派生类总是必须覆盖此方法,并在其中设置第一个名称。当然,您必须使firstname属性受到保护。这不是一种“必须设定”的方法。但至少给你一个提示。或者,也许只需将GetFirstName更改为SetFirstName;)