我如何确保调用所有这些构造函数?

How do I make sure all these constructors are called?

这是关于 c# 构造函数的,之前已被问过几次。但是,问题和答案从来都不适合我的情况:

public abstract class BaseClass {

    public List<int> MyIntegers { get; set; }

    public BaseClass()
    {
        this.MyIntegers = new List<int>();
    }
    public BaseClass(int initialInteger) : this()
    {
        this.MyIntegers.Add(initialInteger);
    }
}

public class DerivedClass : BaseClass
{
    public List<string> MyStrings { get; set; }

    public DerivedClass()
    {
        this.MyStrings = new List<string>();    // does never get initialized
    }
    public DerivedClass(int initialInteger) : base(initialInteger)
    {
        this.MyStrings.Add(initialInteger.ToString()); <-- exception because DerivedClass() is never called
    }
}

// In Program.cs (or where ever)
var derivedClass = new DerivedClass(10); 

上面的代码将失败,因为 DerivedClass 的无参数构造函数从未被调用。所以,List<string> MyStrings没有初始化。

我知道我不能同时使用 base() 和 this() 进行构造函数链接。但我当然可以这样做:

// Workaround      
public DerivedClass(int initialInteger) : base(initialInteger)
{
   this.MyStrings = new List<string>(); // redundant
   this.MyStrings.Add(initialInteger.ToString());
}

这可行,但它非常难看,因为我使用了冗余代码。在简单的示例中似乎没问题,但在我的实际应用程序中,我将不得不添加大量冗余代码。不好看

你会如何优雅地解决这个问题?

根据经验,一个参数很少的构造函数应该委托给一个参数较多的构造函数,理想情况下只有一个构造函数来完成所有实际的初始化。

public abstract class BaseClass {

    public List<int> MyIntegers { get; set; }

    public BaseClass() : this(new List<int>())    {    }
    public BaseClass(int initialInteger) : this(new List<int>(){initialInteger}) {   }
    protected BaseClass(List<int> myIntegers) => MyIntegers = myIntegers;
}

public class DerivedClass : BaseClass
{
    public List<string> MyStrings { get; set; }
    public DerivedClass () : this(new List<string>(), new List<int>())    {    }
    public DerivedClass (int initialInteger) : this(new List<string>(){initialInteger},new List<int>(){initialInteger}) {   }
    protected DerivedClass (List<string> myStrings, List<int> myIntegers) : base(myIntegers) => MyStrings = myStrings;
}

这样做的缺点是某些 initialization-logic 是重复的,即派生的 class 需要创建一个整数列表以提供给 base-class。如果您的创建逻辑过于复杂,它可能暗示您的模型有问题,或者您应该将一些创建逻辑提取到单独的工厂 class。另一个可能有用的工具是反转控制容器。

这假设给定的问题是其他问题的占位符,因为这个特定的问题可以很容易地通过 params int[] initialValues 解决,正如 Damien_The_Unbeliever 在评论中建议的那样。