【发布时间】:2011-05-23 17:01:10
【问题描述】:
也许我所说的问题不是正确的问题,因为我已经知道简短的回答是“你不能”。
情况
我有一个基类,它有一个带有两个参数的重载构造函数。
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;
}
}
该类正在使用枚举
enum BuildingType { None, General, Office, Apartment }
现在我想创建一个子类 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
}
}
我想要什么以及为什么
我希望 Office 类的第二个构造函数同时执行 base(address, price) 构造函数以及 Office 类的默认构造函数。我想调用base(address, price) 构造函数,这样我就不必重复分配基类的所有属性。我想调用 Office 类的默认构造函数,因为它将 BuildingType 属性设置为 BuildingType.Office。
现在我知道我不能使用这样的东西。
public Office(string address, decimal price, string company)
: base(address, price) this()
我是不是做错了什么?
我想知道我的设计是否有问题让我想同时调用 base(address, price) 和 this()。也许我不应该在构造函数中设置 BuildingType 而是在其他地方?我已经尝试为此引入一个字段。
public BuildingType BuildingType = BuildingType.General;
但是我不能在子类中做同样的事情。我将在基类中隐藏 BuildingType 字段,因此我必须在子类中使用 new 运算符。我已经尝试在基类 virtual 中创建 BuildingType,但无法将字段设为虚拟。
在基础构造函数中创建一些东西
在这个简单的示例中,默认构造函数只为某些属性分配默认值。但是 Building 构造函数也可能正在为建筑物创建一个 Foundation,而 Office 默认构造函数可能会创建一个......(想不出什么,但你明白了)。那么你仍然想要执行这两个默认构造函数。
我是不是想错了方向?
更新
根据 Jon Skeet 的回答和 cmets,这是我的新代码。我已将构造函数链接从最不具体更改为最具体。我还将BuildingType 添加到Building 类的构造函数中,使该构造函数受到保护,并将属性设置器设为私有。
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;
}
}
您(Jon Skeet 或其他人)能否对代码的修订版发表评论?
这里没有解决的一个(次要)问题是 Office 类的默认构造函数仍需要提供默认地址(上述代码中的"Unknown Office")。如果未指定地址,我仍然希望让基类的构造函数决定地址。所以这段代码仍然没有完全做我想要的。
我可以通过不在派生类中使用构造函数链接来解决这个问题,而是让每个构造函数直接调用基构造函数。这意味着我会将Office 类的默认构造函数更改为
public Office() : base(BuildingType.Office)
这适用于这个简单的示例,但如果我想在 Office 的每个实例化上执行某种方法,我就必须调用所有构造函数。这就是为什么构造函数链接对我来说听起来是一个更好的主意。
【问题讨论】:
标签: c# constructor