我的课程Foo
有一个必须初始化的字段_customObject
。我还有一个继承自Bar
:
Foo
public abstract class Foo
{
protected CustomObject _customObject;
public Foo()
{
// Do stuff
}
// Other methods that use _customObject
}
public class Bar : Foo
{
// Constructor and other methods
}
我无法在_customObject
中初始化对象Foo
,因为每个继承的子项都包含CustomObject
的不同子项,因此必须在每个子类中初始化它:
public class Bar : Foo
{
public Bar()
{
_customObject = new CustomObjectInherited1();
}
}
public class Baz : Foo
{
public Baz()
{
_customObject = new CustomObjectInherited2();
}
}
其他人要实现从Foo
继承的新类,所以我想知道是否有一种方法可以显示构建时间中的错误,类似于未实现抽象方法时。如果CustomObject
未初始化,则会因使用NullReferenceException
变量而引发_customObject
,并以应用程序崩溃结束。
答案 0 :(得分:8)
您可以向Foo
构造函数添加参数:
public abstract class Foo
{
protected CustomObject _customObject;
public Foo(CustomObject obj)
{
// Do stuff
_customObject = obj;
}
// Other methods that use _customObject
}
然后,您的派生类将被强制调用它,传入CustomObject
或从中派生的内容:
public class Bar : Foo
{
public Bar():base(new CustomObjectInherited1())
{
}
}
不调用基础构造函数将导致编译时错误。这并不能完全保护你,因为有人仍然可以将null
传递给基础构造函数,但至少他们会解释为什么他们在运行时获得NullReferenceError
。
答案 1 :(得分:4)
您可以通过创建一个抽象方法来强制它,该方法要求子类覆盖它。
public abstract class Foo
{
protected abstract CustomObject CreateCustomObject();
}
public class Bar : Foo
{
protected override CustomObject CreateCustomObject()
{
return new BarCustomObject();
}
}
或者我最喜欢的解决方案:通过通用约束强制执行它。
public abstract class Foo<T> : where T : CustomObject, new()
{
protected T _customObject;
public Foo()
{
this.CustomObject = new T();
}
}
public class Bar : Foo<BarCustomObject>
{
}
答案 2 :(得分:1)
“James Thorpe”提供的答案是正确的(我已经赞成它),但我想在这里分享另一种选择: 您可以将类标记为抽象,并引入抽象属性而不是“_customObject”字段。这样,至少第一个初始化程序将被强制实现它。缺点是你将放松后续级别子类的强制执行:
public abstract class Foo
{
protected abstract CustomObject CustomObject {get; }
public Foo()
{
// Do stuff
}
// Other methods that use _customObject
}
public class Bar : Foo
{
// Constructor and other methods
protected override CustomObject CustomObject
{
get { return "X"; }
}
}
此外,使用第一个解决方案,可以在构造函数中验证传入的值 - 但是,这将是运行时验证。