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

1111

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

Например,

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

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

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

  • 24
    Также стоит отметить, что вы можете связать конструкторы в вашем текущем классе, заменив this на base .
Теги:
constructor

10 ответов

1567
Лучший ответ

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

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

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

  • 36
    Я думаю, что вы, возможно, упустили суть. Проблема была в том, чтобы вызвать базовый конструктор в середине переопределенного конструктора. Возможно, тип данных базового конструктора не совпадает, или вы хотите выполнить формование данных перед передачей их по цепочке. Как бы ты совершил такой подвиг?
  • 187
    Если вам нужно вызвать базовый конструктор в середине переопределения, извлеките его в реальный метод базового класса, который вы можете вызвать явно. Предполагается, что базовые конструкторы абсолютно необходимы для безопасного создания объекта, поэтому всегда будет вызываться base.
Показать ещё 6 комментариев
442

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

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 настолько заблокирован, что я обнаруживаю, что делаю это пару раз, но также отмечаю, что это не то, что вам следует делать, если вы можете избежать этого.
  • 0
    Привет @ChrisS, могу ли я использовать как `: base (" Мое сообщение по умолчанию. ")`, Как это использовать?
Показать ещё 7 комментариев
81

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

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);
    }
}
  • 3
    Это может потенциально нарушать принципы SOLID (SRP), потому что ответственность за создание класса связана с любой другой ответственностью, которую класс должен был взять на себя. Можно использовать абстрактную фабрику, но она может добавить ненужную сложность к простому коду. Конечно, нарушение SOLID - это нормально, если вы знаете компромисс и потери, которые он может отразиться на вашей архитектуре (и как исправить любые будущие проблемы, которые могут возникнуть из-за вашего проектного решения).
20
public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message,
      Exception innerException): base(message, innerException)
    {
        //other stuff here
    }
}

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

16

Верно использовать base (что-то) для вызова конструктора базового класса, но в случае перегрузки используйте this ключевое слово

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
  • 6
    Я вижу, что вы пытаетесь объяснить, и вы правы. Если у вас есть два конструктора в одном классе, вы можете ссылаться на один из другого, используя ключевое слово «this», аналогично тому, как вы используете «base» при вызове унаследованного конструктора. Тем не менее, это не то, о чем просил ФП, так что это не то место, где можно добавить это.
12

Из Принципы проектирования каркаса и правила FxCop.:

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

    class MyException : Exception

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

    public class MyException : Exception

3. CA1032: Исключение должно реализовывать стандартные конструкторы.

  • Открытый конструктор без параметров.
  • Открытый конструктор с одним строковым аргументом.
  • Открытый конструктор с одной строкой и Exception (поскольку он может обернуть другое исключение).
  • Конструктор сериализации защищен, если тип не запечатан и не закрыт, если тип запечатан. На основе 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.
      }
    }  
9

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

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

или

public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject)
{
}
  • 1
    Вам не нужно удалять слова "класс" из вашего примера, так как это конструкторы ...
4

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

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 наследуется от базового класса, вам даже не нужно явно вызывать конструктор базового класса. Вы можете просто обновить свойство 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
    this.Message только для чтения, поэтому решение не может работать.
  • 0
    @AndyMiddleditch Нет, это не так. Сеттер просто частный. docs.microsoft.com/en-us/dotnet/api/...
Показать ещё 1 комментарий
4
public class MyException : Exception
{
    public MyException() { }
    public MyException(string msg) : base(msg) { }
    public MyException(string msg, Exception inner) : base(msg, inner) { }
}
  • 1
    это лучший ответ, потому что он также содержит перегрузки конструктора.
4
class Exception
{
     public Exception(string message)
     {
         [...]
     }
}

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню