【发布时间】:2020-10-22 12:58:49
【问题描述】:
我在 SO 上看到了这个问题的许多变体,但解决方案不适用于这种情况。
我有与此类似的代码,但在 Derived 中有冗长的构造函数,我想避免重复。
abstract class Base
{
private int ID;
protected Base( int id )
{
ID = id;
}
protected Base()
{
ID = GenerateID();
}
private int GenerateID()
{
return 42;
}
}
class Derived : Base
{
public readonly int SomeField;
public Derived( int SomeFieldInitialValue ) : base()
{
SomeField = SomeFieldInitialValue;
}
public Derived( int SomeFieldInitialValue, int id ) : base( id )
{
// Want to remove this duplication - could be a long constructor.
// Can't put it in a method because it does things that only constructors can do.
SomeField = SomeFieldInitialValue;
}
}
我无法在 Derived 中创建一个辅助方法来包含所有构造函数共有的代码,因为其中一些代码只能在构造函数中完成(例如,设置只读成员)。
我不能只使用一个基本构造函数并传递默认值,因为用于Base.ID 的值只有Base 知道(在私有GenerateID 方法中计算)。
我不能使用字段初始化器,因为字段在每个构造函数中都没有被初始化为相同的东西,并且它们的值取决于构造函数参数。
我宁愿不将 Base.GenerateID 暴露给派生类以在没有 id 传递的情况下传递,因为没有其他理由公开它,而且将基本功能推入派生类似乎很麻烦。此外,除了一个 int 之外,未来可能还有其他细节 - 根据调用 Base 构造函数的不同,可能需要或不需要运行各种其他代码 - 让 Derived 知道这似乎很糟糕。
我宁愿避免从Derived 的成员中删除readonly,因为它们是readonly 故意的。
我感觉答案将是“抱歉,C# 不允许这样做”,我将不得不在我不想选择的选项之一之间进行选择 :) 我认为该选项是最糟糕的是删除 readonly 或者将这些字段替换为 private set 属性。
【问题讨论】:
-
添加一个选项:将基本c'tor定义为
Base(int? id),如果参数为null,则调用GenerateId。此外,定义private Derived(int SomeFieldInitialValue, int? id)完成所有工作并从公共 c'tors 重定向到这个新的。 -
这个问题有点太抽象了。您可以将基类重构为只有一个构造函数吗?例如。使用工厂方法创建具有生成 id 的实例。然后您可以通过调用
this(...)而不是base(...)来链接派生类构造函数,这会将所有初始化保持在一个地方。 -
同意 Klaus - 因为 Base 构造函数都是受保护的并且类是抽象的 - 将它们组合成一个(接受
int?)不会损害“公共”使用(不会使其不那么方便),同时解决继承类的问题。
标签: c# inheritance constructor