Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强制子类初始化变量_C#_.net_Inheritance - Fatal编程技术网

C# 强制子类初始化变量

C# 强制子类初始化变量,c#,.net,inheritance,C#,.net,Inheritance,我有一个类Foo,它有一个必须初始化的字段\u customObject。我还有一个从Foo继承的类Bar: public abstract class Foo { protected CustomObject _customObject; public Foo() { // Do stuff } // Other methods that use _customObject } public class Bar : Foo {

我有一个类
Foo
,它有一个必须初始化的字段
\u customObject
。我还有一个从
Foo
继承的类
Bar

public abstract class Foo
{
    protected CustomObject _customObject;

    public Foo()
    {
        // Do stuff
    }
    // Other methods that use _customObject
}

public class Bar : Foo
{
    // Constructor and other methods
}
我无法在
Foo
中初始化对象
\u customObject
,因为继承的每个子对象都包含
customObject
的不同子对象,因此必须在每个子类中初始化它:

public class Bar : Foo
{
    public Bar()
    {
        _customObject = new CustomObjectInherited1();
    }
}


public class Baz : Foo
{
    public Baz()
    {
        _customObject = new CustomObjectInherited2();
    }
}

其他人将要实现从
Foo
继承的新类,因此我想知道是否有一种方式显示构建时的错误,类似于未实现抽象方法时的错误。如果未初始化
CustomObject
,由于使用
\u CustomObject
变量,将引发
NullReferenceException
,最终导致应用程序崩溃。

您可以向
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
传递给基构造函数,但至少他们会解释为什么在运行时会出现
null引用错误。

您可以通过创建一个抽象方法来强制它,该方法要求子类重写它

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>
{
}
公共抽象类Foo:where T:CustomObject,new()
{
受保护的T_自定义对象;
公共食物(
{
this.CustomObject=new T();
}
}
公共类酒吧:富
{
}
詹姆斯·索普(James Thorpe)提供的答案是正确的(我已经投了更高的票),但我想在这里分享另一个选择: 您可以将类标记为抽象类,并引入一个抽象属性,而不是“\u 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"; }
    }
}

此外,对于第一个解决方案,可以在构造函数中验证传入的值—不过,这将是一个运行时验证。

我认为这实际上是一个很好的问题。我怀疑否决票是由于被要求的级别。但是,事实上,即使是关于简单概念的问题也显示出很大的努力和清晰的提问。这是关于改进设计的,我喜欢+1.@JamesThorpe这很公平。我只是觉得杰米的回答更强调了OP想要知道的。这是一个很好的答案。我认为这个答案的第一部分是最正确的,因为它更明确地说,“嘿,你必须这样做”。由于软件产品的大部分成本都是在长期的维护过程中产生的,我非常喜欢保持它的简单。@JClark4321在这种情况下没有“更正确的”了。我使用了两种方法,这取决于哪种方法更适合解决当前的问题。“最佳”答案是使用带有上下文绑定的依赖项注入,但这只有在您已经使用了IOC容器时才有意义。只有当我们知道
BarCustomObject
的构造函数的样子时,这两种解决方案才能起作用。例如,它将具有哪些参数。@Aldarrion好吧,最初的问题是
强制子类初始化变量
是,这意味着知道如何初始化变量,是否强制执行它。但您可以轻松地将任务委托给IOC容器或使用工厂模式。