如何让重载的构造函数调用默认构造函数以及基本构造函数的重载?

com*_*cme 47 c# constructor

也许我说过的问题不是正确的问题,因为我已经知道简短的回答是"你不能".

情况

我有一个带有重载构造函数的基类,它带有两个参数.

class Building
{
    public BuildingType BuildingType { get; protected set; }
    public string Address { get; set; }
    public decimal Price { get; set; }

    public Building()
    {
        BuildingType = BuildingType.General;
        Address = "Unknown";
    }

    public Building(string address, decimal price)
        : this()
    {
        Address = address;
        Price = price;
    }
}
Run Code Online (Sandbox Code Playgroud)

该课程正在使用枚举

enum BuildingType { None, General, Office, Apartment }
Run Code Online (Sandbox Code Playgroud)

现在我想创建一个子类Office,它也有一个重载的构造函数.这个子类添加了另一个属性(公司).在此类中,BuildingType属性当然应设置为Office.这是代码.

class Office : Building
{
    public string Company { get; set; }

    public Office()
    {
        BuildingType = BuildingType.Office;
    }

    public Office(string address, decimal price, string company)
        : base(address, price)
    {
        Company = company;
        // BuildingType = BuildingType.Office; // Don't wanna repeat statement
    }
}
Run Code Online (Sandbox Code Playgroud)

我想要什么,为什么

我希望Office类的第二个构造函数既可以执行base(address, price)构造函数,也可以执行Office类的默认构造函数.我想调用base(address, price)构造函数,所以我不必重复分配基类的所有属性.我想调用Office类的默认构造函数,因为它将BuildingType属性设置为BuildingType.Office.

现在我知道我不能使用这样的东西.

public Office(string address, decimal price, string company)
    : base(address, price) this()
Run Code Online (Sandbox Code Playgroud)

难道我做错了什么?

我想知道我的设计是否有问题让我想要同时调用base(地址,价格)和this().也许我不应该在构造函数中设置BuildingType而在其他地方?我试图为此引入一个字段.

    public BuildingType BuildingType = BuildingType.General;
Run Code Online (Sandbox Code Playgroud)

但后来我不能在子课上做同样的事.我将隐藏基类中的BuildingType字段,因此我必须new在子类中使用运算符.我已经尝试在基类中创建BuildingType virtual,但是不能将字段设置为虚拟.

在基础构造函数中创建一些东西

在这个简单的示例中,默认构造函数仅为某些属性分配默认值.但构建构造函数也可以为构建创建一个Foundation,而Office默认构造函数可能会创建一个......(想不出什么,但是你明白了).那么你仍然想要执行两个默认构造函数.

我在这里想错了方向吗?


更新

根据Jon Skeet的回答和评论,这是我的新代码.我已经将构造函数链接从最不具体到最具体.我还添加了类BuildingType的构造函数Building,使该构造函数受到保护,并使属性setter成为私有.

enum BuildingType { None, General, Office, Apartment }

class Building
{
    private const string DefaultAddress = "Unknown";

    public BuildingType BuildingType { get; private set; }
    public string Address { get; set; }
    public decimal Price { get; set; }

    #region Optional public constructors
    // Only needed if code other than subclass must 
    // be able to create a Building instance.
    // But in that case, the class itself can be abstract
    public Building() : this(DefaultAddress, 0m)
    {}

    public Building(string address, decimal price)
        : this(BuildingType.General, address, price) 
    {}
    #endregion

    protected Building(BuildingType buildingType)
        : this(buildingType, DefaultAddress, 0m) 
    {}

    protected Building(BuildingType buildingType,
        string address, decimal price)
    {
        BuildingType = buildingType;
        Address = address;
        Price = price;
    }
}

class Office : Building
{
    public string Company { get; set; }

    public Office() : this("Unknown Office", 0m, null) 
    {}

    public Office(string address, decimal price, string company)
        : base(BuildingType.Office, address, price)
    {
        Company = company;
    }
}
Run Code Online (Sandbox Code Playgroud)

您(Jon Skeet或其他人)可以对此修订版的代码发表评论吗?

未解决的一个(次要)问题是Office类的默认构造函数仍需要提供默认地址("Unknown Office"在上面的代码中).如果没有指定地址,我仍然希望让基类的构造函数决定地址.所以这段代码仍然没有完全符合我的要求.

我可以通过在派生类中不使用构造函数链来解决这个问题,但是相反,它的每个构造函数都直接调用基础构造函数.这意味着我Office要将类的默认构造函数更改为

public Office() : base(BuildingType.Office)
Run Code Online (Sandbox Code Playgroud)

这适用于这个简单的例子,但如果有一些方法我想在Office的每个实例化上执行,我必须在所有构造函数中调用.这就是构造链接对我来说听起来更好的原因.

Jon*_*eet 54

你的方法不是传统方法,它可以解决问题.而不是使更具体的构造函数(具有大量参数的构造函数)调用无参数的构造函数,而是反过来做事 - 使无参数调用另一个调用另一个,提供默认值.这通常导致所有构造函数在每个类中调用一个"主"(可能是间接的,通过其他),并且"主"构造函数调用进行基本构造函数调用.

class Office : Building
{
    public string Company { get; set; }

    public Office() : this(null, 0m, null)
    {
    }

    public Office(string address, decimal price, string company)
        : base(address, price)
    {
        Company = company;
        BuildingType = BuildingType.Office; // Don't wanna repeat statement
    }
}
Run Code Online (Sandbox Code Playgroud)

......和基类相同:

class Building
{
    public BuildingType BuildingType { get; protected set; }
    public string Address { get; set; }
    public decimal Price { get; set; }

    public Building() : this("Unknown", 0m)
    {
    }

    public Building(string address, decimal price)
    {
        BuildingType = BuildingType.General;
        Address = address;
        Price = price;
    }
}
Run Code Online (Sandbox Code Playgroud)

(我会认真考虑让Building构造函数包含一个BuildingType参数.)