简体   繁体   English

调用不同的基本构造函数时如何避免构造函数之间的重复

[英]How to avoid duplication between constructors when they call different base constructors

I have seen many variants of this question asked on SO, but the solutions don't apply in this case.我在 SO 上看到了这个问题的许多变体,但解决方案不适用于这种情况。

I have code similar to this, but with lengthy constructors in Derived , which I'd like to avoid duplicating.我有与此类似的代码,但在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;
    }
}

I can't create a helper method in Derived to contain the code common to all constructors, since some of that code can only be done in constructors (eg setting readonly members).我无法在Derived创建一个辅助方法来包含所有构造函数通用的代码,因为其中一些代码只能在构造函数中完成(例如设置只读成员)。

I can't use just one base constructor and pass along default values, as the value that would get used for Base.ID is known only to Base (computed in the private GenerateID method).我不能只使用一个基本构造函数并传递默认值,因为用于Base.ID值只有Base知道(在私有GenerateID方法中计算)。

I can't use field initializers, as fields aren't initialised to the same thing in each constructor, and their values depend on constructor parameters.我不能使用字段初始值设定项,因为字段在每个构造函数中没有被初始化为相同的东西,它们的值取决于构造函数参数。

I'd rather not expose Base.GenerateID to derived classes to pass along in the absence of an id to pass along, as there's no other reason to expose it, and it seems messy to push base functionality up into derived classes.在没有要传递的 id 的情况下,我宁愿不将Base.GenerateID公开给派生类来传递,因为没有其他理由公开它,而且将基本功能推入派生类似乎很麻烦。 Also there are likely to be other details in future beyond just an int - there's all sorts of other code that may or may not need to be run depending on which Base constructor is called - giving Derived knowledge of that seems bad.此外,未来可能还会有其他细节,而不仅仅是 int - 根据调用的Base构造函数,可能需要或不需要运行各种其他代码 - 提供Derived知识似乎很糟糕。

I'd rather avoid removing the readonly from members of Derived as they're readonly on purpose.我宁愿避免从Derived成员中删除readonly ,因为它们是故意readonly

I have a feeling that the answer is going to be "sorry, C# doesn't allow that" and I'll have to pick between one of the options I don't want to take :) I think the option that's least bad is to remove readonly or perhaps replace those fields with private set properties.我有一种感觉,答案将是“对不起,C# 不允许这样做”,我必须在我不想采取的选项之一中进行选择:) 我认为最不坏的选项是删除readonly或可能用private set属性替换这些字段。

If you can change the base class, it would be better to have only a single constructor there.如果您可以更改基类,那么最好只有一个构造函数。 This could then provide the two options (fixed ID or newly generated ID) like so:这可以提供两个选项(固定 ID 或新生成的 ID),如下所示:

abstract class Base
{
    private int ID;

    protected Base( int? id )
    {
        ID = id ?? GenerateID();
    }

    private int GenerateID()
    {
        return 42;
    }
}

Also in the derived class, define a (private or protected) constructor doing all the heavy work, and then public constructors redirecting to this.同样在派生类中,定义一个(私有或受保护的)构造函数来完成所有繁重的工作,然后公共构造函数重定向到这个。

class Derived : Base
{
    public readonly int SomeField;
    
    protected Derived( int SomeFieldInitialValue, int? id ) : base(id)
    {
        SomeField = SomeFieldInitialValue;
    }
    
    public Derived( int SomeFieldInitialValue ) : this( SomeFieldInitialValue, null)
    {
    }

    public Derived( int SomeFieldInitialValue, int id ) : this( SomeFieldInitialValue, id )
    {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM