Вызов базового конструктора в C#


1,073

Если я наследую базовый класс и хочу передать что-то из конструктора унаследованного класса конструктору базового класса, как это сделать?

Например,

Если я наследовать от класса Exception Я хочу сделать что-то вроде этого:

class MyExceptionClass : Exception 
{ 
    public MyExceptionClass(string message, string extraInfo) 
    { 
     //This is where it's all falling apart 
     base(message); 
    } 
} 

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

+17

Его также стоит отметить, вы можете цепи конструкторами в текущем классе, заменяя '' this' для base'. 15 авг. 082008-08-15 13:30:04

1,380

Измените конструктор к следующему, так что он вызывает конструктор базового класса правильно:

public class MyExceptionClass : Exception 
{ 
    public MyExceptionClass(string message, string extrainfo) : base(message) 
    { 
     //other stuff here 
    } 
} 

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

+24

Я думаю, вы, возможно, пропустили точку. Проблема заключалась в вызове базового конструктора на полпути через конструктор overriden. Возможно, тип данных базового конструктора не то же самое или вы хотите сделать некоторое формование данных, прежде чем передавать его по цепочке. Как бы вы совершили такой подвиг? 16 фев. 092009-02-16 21:03:32

+165

Если вам нужно вызвать базовый конструктор в середине переопределения, то извлеките его в фактический метод в базовом классе, который вы можете вызвать явно. Предположение с базовыми конструкторами состоит в том, что они абсолютно необходимы для безопасного создания объекта, поэтому база будет вызываться сначала, всегда. 17 фев. 092009-02-17 10:46:38

+28

Это _is_ просто метод, который вы можете вызвать в любое время, IL-мудрый. C# просто накладывает дополнительные ограничения на это. 17 апр. 112011-04-17 03:03:18

+1

@romkyns Для класса да. Для структуры нет. C# не позволяет вам вызывать базовый конструктор для структур, чтобы убедиться, что они остаются (вроде) здравомыслящими, а для классов - держать вещи одинаково по всем направлениям. (Сравните с C++, где то же самое верно, за исключением того, что хранимый в стеке или выбор кучи выполняется в вызывающем коде, а не в коде класса, и такое же ограничение существует) 22 мар. 142014-03-22 19:18:53

+6

Стоит отметить, что Конструктор 'base' называется _before_, к которому обращается блок метода. https://msdn.microsoft.com/en-us/library/ms173115.aspx 08 дек. 152015-12-08 16:27:51

+10

Это не очень хороший дизайн, если вам нужно вызвать конструктор базового класса посередине во время вашего конструктора. Идея конструктора состоит в том, что он выполняет всю работу, необходимую для выполнения своей задачи. Это приводит к тому, что при запуске вашего производного конструктора базовый класс уже полностью инициализирован и производный класс может вызвать любую функцию базового класса.Если ваш дизайн таков, что вы хотите сделать что-то наполовину своего конструктора, то, по-видимому, это не инициализация базового класса ans, поэтому он не должен находиться в конструкторе базового класса, а в отдельной, возможно защищенной функции 16 дек. 152015-12-16 07:28:27

  0

@JonLimjap делает это означает, что вы не можете реализовать шаблон метода шаблона с помощью конструктора? 10 янв. 172017-01-10 21:25:00

+1

@Sebastien Да и нет. Если ваш конструктор действует как ваш метод шаблона, вызывающий другие примитивные операции (абстрактные методы), тогда его можно реализовать. Любая другая реализация, требующая вызова конструктора явно из другого метода или другого переопределения конструктора - это то, что запрещено. 11 янв. 172017-01-11 02:27:54

  0

Самый простой 10 000 rep в истории переполнения стека ... 17 янв. 182018-01-17 07:08:07

  0

@ DaffyPunk Я просто думал, что сам себя. 15 фев. 182018-02-15 19:05:09


21
public class MyExceptionClass : Exception 
{ 
    public MyExceptionClass(string message, 
     Exception innerException): base(message, innerException) 
    { 
     //other stuff here 
    } 
} 

Вы можете передать внутреннее исключение одному из конструкторов.


398

Обратите внимание, что вы можете использовать статические методы в вызове базовому конструктору.

class MyExceptionClass : Exception 
{ 
    public MyExceptionClass(string message, string extraInfo) : 
     base(ModifyMessage(message, extraInfo)) 
    { 
    } 

    private static string ModifyMessage(string message, string extraInfo) 
    { 
     Trace.WriteLine("message was " + message); 
     return message.ToLowerInvariant() + Environment.NewLine + extraInfo; 
    } 
} 
+1

Класс Exception настолько заблокирован, что я нахожу себя в этом пару раз, но также отмечаю, что вам нечего делать, если вы можете его избежать. 11 мар. 152015-03-11 19:02:55

  0

Привет @ChrisS, могу ли я использовать как ': base (« Мое сообщение по умолчанию. »)', Как это использовать? 15 май. 152015-05-15 18:32:22

  0

Извините, C# newb здесь. Почему вы называете «Trace.WriteLine (« сообщение было «+ сообщение»)? 09 июл. 152015-07-09 22:08:11

+4

@kdbanman Это просто выводит сообщение отладки. Не существует соответствующего функционального назначения. 21 авг. 152015-08-21 13:52:17

  0

Это не выглядит очень ТВОЙ (если вы знаете, что я имею в виду) (... SRP ...) 10 янв. 172017-01-10 21:27:49

+1

Отличный ответ. [Принятый ответ] (https://stackoverflow.com/a/12052/1175496) не позволяет мне обрабатывать; и [комментарий по обходному пути] (https://stackoverflow.com/questions/12051/calling-the-base-constructor-in-c-sharp#comment367745_12052) предполагает, что у меня есть доступ к изменению базового класса; Я не. [Заводской ответ] (https://stackoverflow.com/a/15103087/1175496) предполагает, что я могу контролировать способ создания класса; Я не могу. Только ваш ответ позволяет мне что-то изменить, прежде чем передавать его на базу. 26 май. 172017-05-26 21:38:59

  0

Абсолютно ничего вредного в этом нет, пока промежуточная функция морально без гражданства. Журналирование не является хорошим вариантом использования, ИМО, но нормализация корпуса или добавление дополнительных кажется прекрасным. 20 июл. 172017-07-20 22:47:19

  0

Большое спасибо за это, мне нужно было создать контекст базы данных с помощью 'using', чтобы получить значение для перехода к базовому конструктору, и я понятия не имел, как это сделать. 12 ноя. 172017-11-12 15:55:00


73

Если вам нужно вызвать базовый конструктор, но не сразу, потому что ваш новый (производный) класс должен сделать некоторые манипуляции с данными, лучшим решением является прибегнуть к заводским способом. Что вам нужно сделать, это отметить частный производный конструктор, а затем создать в своем классе статический метод, который сделает все необходимое, а затем вызовет конструктор и вернет объект.

public class MyClass : BaseClass 
{ 
    private MyClass(string someString) : base(someString) 
    { 
     //your code goes in here 
    } 

    public static MyClass FactoryMethod(string someString) 
    { 
     //whatever you want to do with your string before passing it in 
     return new MyClass(someString); 
    } 
} 
+1

Это может ** потенциально ** нарушать принципы SOLID (SRP), поскольку ответственность за создание класса инкапсулируется с любой другой ответственностью, которую класс должен был позаботиться. Можно использовать абстрактную фабрику, но она может добавить ненужную сложность в простой код. Конечно, нарушение SOLIDs нормально, если вы знаете компромисс и стоимость, которую он собирается наложить на вашу архитектуру (и как исправить любые будущие проблемы, которые могут возникнуть из вашего дизайнерского решения). 10 янв. 172017-01-10 21:22:28


14

Это верно использовать основание (что-то), чтобы вызвать конструктор базового класса, но в случае перегрузки использовать это ключевое слово

public ClassName() : this(par1,par2) 
{ 
// do not call the constructor it is called in the this. 
// the base key- word is used to call a inherited constructor 
} 

// Hint used overload as often as needed do not write the same code 2 or more times 
+4

Я вижу, что вы пытаетесь объяснить, и вы правы. Если у вас есть два конструктора в одном классе, вы можете ссылаться друг на друга, используя ключевое слово «this» аналогично тому, как вы используете «базу» при вызове унаследованного конструктора. Однако это не то, о чем попросил ОП, поэтому на самом деле это не место, чтобы добавить это. 04 дек. 132013-12-04 14:35:52


4
class Exception 
{ 
    public Exception(string message) 
    { 
     [...] 
    } 
} 

class MyExceptionClass : Exception 
{ 
    public MyExceptionClass(string message, string extraInfo) 
    : base(message) 
    { 
     [...] 
    } 
} 

13

Из Framework Design Guidelines и правил FXCop.:

1. Пользовательские исключения должны иметь имя, которое заканчивается Exception

class MyException : Exception 

2. Исключение должно быть публичным

public class MyException : Exception 

3. CA1032: Exception should implements standard constructors.

  • Открытый конструктор без параметров.
  • Открытый конструктор с одним аргументом строки.
  • Публичный конструктор с одной строкой и исключение (поскольку он может обернуть другое исключение).
  • Конструктор сериализации защищен, если тип не запечатан и не закрыт, если тип запечатан. основе MSDN:

    [Serializable()] 
    public class MyException : Exception 
    { 
        public MyException() 
        { 
        // Add any type-specific logic, and supply the default message. 
        } 
    
        public MyException(string message): base(message) 
        { 
        // Add any type-specific logic. 
        } 
        public MyException(string message, Exception innerException): 
        base (message, innerException) 
        { 
        // Add any type-specific logic for inner exceptions. 
        } 
        protected MyException(SerializationInfo info, 
        StreamingContext context) : base(info, context) 
        { 
        // Implement type-specific serialization constructor logic. 
        } 
    } 
    

или

[Serializable()] 
    public sealed class MyException : Exception 
    { 
     public MyException() 
     { 
     // Add any type-specific logic, and supply the default message. 
     } 

     public MyException(string message): base(message) 
     { 
     // Add any type-specific logic. 
     } 
     public MyException(string message, Exception innerException): 
     base (message, innerException) 
     { 
     // Add any type-specific logic for inner exceptions. 
     } 
     private MyException(SerializationInfo info, 
     StreamingContext context) : base(info, context) 
     { 
     // Implement type-specific serialization constructor logic. 
     } 
    } 

3
public class MyException : Exception 
{ 
    public MyException() { } 
    public MyException(string msg) : base(msg) { } 
    public MyException(string msg, Exception inner) : base(msg, inner) { } 
} 

6

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

public MyClass(object myObject=null): base(myObject ?? new myOtherObject()) 
{ 
} 

или

public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject) 
{ 
} 
+1

Вам не нужно удалять слова «класс» из вашего примера, так как это конструкторы ... 27 сен. 162016-09-27 04:50:43

  0

@MarzSocks действительно, спасибо! 27 сен. 162016-09-27 14:29:44


3

В соответствии с некоторыми из других ответов, перечисленных здесь, вы можете передать параметры в конструктор базового класса. Рекомендуется назначить конструктор базового класса в начале конструктора для вашего унаследованного класса.

public class MyException : Exception 
{ 
    public MyException(string message, string extraInfo) : base(message) 
    { 
     this.Message = $"{message} Extra info: {extraInfo}"; 
     // You can omit the 'this.' portion above... 
    } 
} 

Хочу отметить, что в вашем примере вы никогда не делали использование параметра extraInfo, поэтому я предположил, что вы можете сцепить параметр extraInfo строки в Message свойство вашего исключения (это, кажется, что это игнорируется в принятый ответ и код в вашем вопросе).

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

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

public class MyException : Exception 
{ 
    public MyException(string message, string extraInfo) 
    { 
     this.Message = $"{message} Extra info: {extraInfo}"; 
     // You can omit the 'this.' portion above... 
    } 
} 
  0

Почему downvote? 18 мар. 172017-03-18 22:09:48

  0

жаль, что ты прав. Я не заметил, что код пришел дословно из вопроса, который я извиняюсь. Как я уже говорил, я не сделал ни слова, так что еще нечего сказать, но вы могли бы хотя бы предоставить некоторую информацию в этом ответе, чтобы сделать ее как-то ценной. 23 июл. 172017-07-23 17:05:14