Абстрактный класс с конструктором, заставить унаследованный класс вызывать его

Возможно, дубликат, у меня есть абстрактный класс с конструктором XYZ (имя строки). Также у меня есть класс, который наследует от этого абстрактного класса. Как заставить унаследованный класс вызывать базу (имя строки)? Теперь я могу использовать новый Inherited(), и он не будет вызывать базовую конструкцию. Я хочу заставить пользователя реализовать конструктор по умолчанию в унаследованном классе.

4 ответа

Решение

Класс без явного конструктора имеет конструктор без параметров. С другой стороны, если вы реализуете конструктор с параметрами и без беспараметрического конструктора, ваш класс не будет создан без аргументов.

Другими словами:

public abstract class A 
{
    public A(string x) 
    {
    }
}

public class B : A 
{
    // If you don't add ": base(x)" 
    // your code won't compile, because A has a 
    // constructor with parameters!
    public B(string x) : base(x)
    {
    }
}

То есть если A имеет конструктор без параметров (или без явного конструктора), B автоматически вызовет базовый конструктор. Вам не нужно кодировать дальнейшие вещи здесь.

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

Временное решение

Ну, здесь нет особого обходного пути, но имейте в виду, что C# поддерживает необязательные параметры как в конструкторах, так и в методах.

Если вы хотите быть на 100% уверены, что производные классы будут вызывать конкретный базовый конструктор, вы можете реализовать свой базовый класс, используя один конструктор без параметров с необязательными параметрами, и использовать его вместо перегрузки конструктора:

public class A
{
    public A(string x = "hello world") // or just string x = null
    {

    }
}

Теперь, если B производный класс A, B всегда буду звонить Aконструктор, т.к. x не является обязательным и имеет значение по умолчанию.

Как заставить унаследованный класс вызывать base(string name)

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

public abstract class BaseClass
{
    protected BaseClass(string parameter)
    {
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass()
    {
    }
}

В конечном итоге

'`Project.BaseClass`' does not contain a constructor that takes 0 arguments

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

Я провел последние полчаса или около того, экспериментируя еще раз с перестановками абстрактного базового класса, конструктор по умолчанию которого помечен как закрытый, и перегрузкой, которая принимает 4 параметра, и производным классом, который имеет только перегрузку из 4 параметров. Используя последний компилятор C# (7.3), очевидно, что в этой ситуации:

  1. Производный класс должен явно определять перегрузку с 4 параметрами.
  2. Перегрузка в вызове производного класса для перегрузки с 4 параметрами должна быть явной.

Подпись конструктора базового класса

public OperatingParameterBase (
    string pstrInternalName ,
    string pstrDisplayName ,
    T penmParameterType ,
    U penmDefaultParameterSource )

Конструктор производного класса

internal OperatingParameter (
    string pstrInternalName ,
    string pstrDisplayName ,
    T penmParameterType ,
    U penmDefaultParameterSource )
    : base (
          pstrInternalName ,
          pstrDisplayName ,
          penmParameterType ,
          penmDefaultParameterSource )
{
}   // internal OperatingParameterExample constructor

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

Другие вопросы по тегам