Автоматически сделать базовые конструкторы доступными в производном классе? - PullRequest
19 голосов
/ 19 января 2010

У меня есть базовый класс с двумя конструкторами, требующий параметр:

public abstract class StoreBase 
{
    private readonly SomeObject_sobj;

    protected StoreBase(SomeObject sobj)
    {
        _sobj = sobj;
    }

    protected StoreBase(OtherObject oobj)
    {
        _sobj = new SomeObject(oobj);
    }
}

Тогда у меня есть производный класс:

public class MyDerived: StoreBase
{

}

Это вызывает ошибку компиляции как base class doesn't contain parameterless constructor.

Насколько я понимаю, поскольку MyDerived не содержит конструктора, компилятор добавляет конструктор без параметров (это хорошо известно и не имеет ничего общего с производными классами). Однако, поскольку он наследуется от другого класса, конструктор базового класса должен запускаться первым, и нет способа определить, какой конструктор должен запускаться из пустого конструктора MyDerived.

По сути, я спрашиваю: могу ли я избежать копирования / вставки всех конструкторов из Base в класс Derived, если мне действительно не нужна дополнительная логика конструктора? Можно ли сказать «взять все конструкторы из базы», ​​не добавляя их всех?

(И да, я знаю, что могу / должен преобразовать это в конструктор без параметров и в защищенный виртуальный метод Initialize (). Но я все еще задаюсь вопросом, могу ли я работать с конструкторами и все же избежать копирования / вставки)

Ответы [ 5 ]

15 голосов
/ 19 января 2010

Нет - вам также потребуется реализовать (соответствующие) конструкторы в производном классе.

Производный класс должен использовать только один из базовых конструкторов - поэтому требуемые в нем конструкторы могут полностью отличаться от базового класса. Они должны быть реализованы вручную, даже если это просто:

public class MyDerived : StoreBase
{
     public MyDerived(SomeObject sobj) : base(sobj) {}
     public MyDerived(OtherObject  oobj) : base(oobj) {}
}

Также:

(И да, я знаю, что мог бы / должен преобразовать это в конструктор без параметров и в защищенный виртуальный метод Initialize (). Но мне все еще интересно, смогу ли я работать с конструкторами и все же избежать копирования / вставки)

Хотя я вижу, что это рекламируется, я считаю, что это не всегда хорошая практика. Во многих случаях это на самом деле проблематично, поскольку вы полагаетесь на подкласс для правильного вызова Initialize, если они переопределяют ваш защищенный виртуальный метод. Например, если подкласс сделал это, он мог бы быть очень плохим:

public class MyDerived : StoreBase
{
   // .. other stuff
   protected override void Initialize()
   {
       // Leave out, intentionally or accidentally, the following:
       // base.Initialize(); 
   }
}

Я фактически избегаю этого в большинстве ситуаций и инициализирую в конструкторах (или в частном, не виртуальном методе инициализации). Невыполнение этого требования нарушает все ваши гарантии, что ваша инициализация всегда будет происходить так, как вы собираетесь.

Конструкторы и цепочка конструкторов обеспечивают одинаковую функциональность с гораздо лучшими гарантиями.

3 голосов
/ 19 января 2010

Компилятор будет генерировать конструктор по умолчанию (без параметров), если вы сами не предоставили конструктор. Как только вы определите конструктор, компилятор не сгенерирует его для вас.

Это может быть важно иметь в виду, если вы планируете сериализацию своего класса, поскольку для сериализации требуется конструктор по умолчанию. Если вы дадите вашему классу конструктор, отличный от конструктора по умолчанию, то вам также необходимо будет предоставить конструктор по умолчанию для поддержки сериализации, потому что, опять же, как только вы предоставите какой-либо конструктор, компилятор не будет для вас автоматически.

3 голосов
/ 19 января 2010

Нет, конструкторы не наследуются, и ярлык для создания копий базовых конструкторов отсутствует.

Наиболее близким является реализация конструкторов, которые вызывают базовые конструкторы. Я предполагаю, что вы все равно хотите сделать их публичными, чтобы вы могли создать экземпляр класса:

public MyDerived(SomeObject sobj) : base(sobj) {}
public MyDerived(OtherObject oobj) : base(oobj) {}
2 голосов
/ 19 января 2010

К сожалению, ответ нет.

Одна вещь, которую вы можете сделать, это вызвать базу из вашего конструктора MyDerived:

class MyDerived: StoreBase
{
public MyDerived(OtherObject obj) : base (obj) {}
}
1 голос
/ 19 января 2010

Могу ли я сказать «Взять все конструкторы из базы», ​​не добавляя их все?

Нет.: - (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...