强制子类初始化变量

时间:2016-03-09 16:55:25

标签: c# .net inheritance

我的课程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,并以应用程序崩溃结束。

3 个答案:

答案 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"; }
    }
}

此外,使用第一个解决方案,可以在构造函数中验证传入的值 - 但是,这将是运行时验证。