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

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

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

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

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

15.08.2008 07:39:23
Его также стоит отметить , вы можете конструкторы цепи в текущем классе, подставляя thisдля base.
Quibblesome 15.08.2008 13:30:04
11 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

1827
15.08.2008 07:48:56
Я думаю, что вы, возможно, упустили момент. Проблема была в том, чтобы вызвать базовый конструктор в середине переопределенного конструктора. Возможно, тип данных базового конструктора не совпадает, или вы хотите выполнить формование данных перед передачей их по цепочке. Как бы ты совершил такой подвиг?
Marchy 16.02.2009 21:03:32
Если вам нужно вызвать базовый конструктор в середине переопределения, извлеките его в реальный метод базового класса, который вы можете вызвать явно. Предполагается, что базовые конструкторы абсолютно необходимы для безопасного создания объекта, поэтому всегда будет вызываться base.
Jon Limjap 17.02.2009 10:46:38
Это является просто методом вы можете позвонить в любое время, IL-накрест. Просто C # накладывает на это дополнительные ограничения.
Roman Starkov 17.04.2011 03:03:18
Стоит отметить, что baseконструктор вызывается до обращения к блоку метода. msdn.microsoft.com/en-us/library/ms173115.aspx
John Weisz 8.12.2015 16:27:51
Это не очень хороший дизайн, если вам нужно вызвать конструктор базового класса в середине вашего конструктора. Идея конструктора заключается в том, что он выполняет всю работу, необходимую для выполнения своей задачи. Это приводит к тому, что при запуске вашего производного конструктора базовый класс уже полностью инициализирован и производный класс может свободно вызывать любую функцию базового класса. Если ваш дизайн таков, что вы хотите сделать что-то наполовину с вашим конструктором, то, очевидно, это не инициализация базового класса и, следовательно, не в конструкторе базового класса, а в отдельной, возможно защищенной функции
Harald Coppoolse 16.12.2015 07:28:27
public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message,
      Exception innerException): base(message, innerException)
    {
        //other stuff here
    }
}

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

28
4.12.2009 05:03:34

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

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;
     }
}
508
31.08.2015 17:17:17
Класс Exception настолько заблокирован, что я обнаруживаю, что делаю это пару раз, но также учтите, что это не то, что вам следует делать, если вы можете избежать этого.
Jonathon Cwik 11.03.2015 19:02:55
Привет @ChrisS, могу ли я использовать как `: base (" Мое сообщение по умолчанию. ")`, Как это использовать?
Carlos 15.05.2015 18:32:22
@kdbanman Это просто выводит сообщение отладки. Нет соответствующего функционального назначения.
Nick Whaley 21.08.2015 13:52:17
Отличный ответ. Принятый ответ не позволяет мне выполнять обработку; и последующий комментарий к обходному решению предполагает, что у меня есть доступ для изменения базового класса; Я не. Заводской ответ предполагает, что я могу контролировать, как создается экземпляр класса; Я не могу Только ваш ответ позволяет мне что-то изменить, прежде чем передать это на базу.
The Red Pea 26.05.2017 21:38:59
Если вы находитесь в ситуации, описанной выше. Вместо наследования вы можете построить свой класс как обертку базового класса в качестве альтернативного решения.
DonO 10.07.2018 20:31:32

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

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);
    }
}
101
7.04.2013 20:52:07
Это может потенциально нарушать принципы SOLID (SRP), потому что ответственность за создание класса связана с любой другой ответственностью, которую класс должен был взять на себя. Можно использовать абстрактную фабрику, но она может добавить ненужную сложность к простому коду. Конечно, нарушение SOLID - это нормально, если вы знаете компромисс и потери, которые он может оказать на вашу архитектуру (и как исправить любые будущие проблемы, которые могут возникнуть из-за вашего проектного решения).
Sebastien 10.01.2017 21:22:28

Это правда, используйте 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
38
9.04.2018 11:46:52
Я вижу, что вы пытаетесь объяснить, и вы правы. Если у вас есть два конструктора в одном классе, вы можете ссылаться на один из другого, используя ключевое слово «this», аналогично тому, как вы используете «base» при вызове унаследованного конструктора. Однако, это не то, о чем просил ФП, так что это не то место, где можно добавить это.
IAmTimCorey 4.12.2013 14:35:52
class Exception
{
     public Exception(string message)
     {
         [...]
     }
}

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo)
     : base(message)
     {
         [...]
     }
}
9
26.02.2015 04:11:37

Из Руководства по разработке рамок и правил FxCop. :

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

    class MyException : Exception

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

    public class MyException : Exception

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

  • Открытый конструктор без параметров.
  • Открытый конструктор с одним строковым аргументом.
  • Открытый конструктор с одной строкой и исключением (так как он может обернуть другое исключение).
  • Конструктор сериализации защищен, если тип не запечатан, и закрытый, если тип запечатан. Основано на 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.
      }
    }  
20
24.01.2016 07:34:21
public class MyException : Exception
{
    public MyException() { }
    public MyException(string msg) : base(msg) { }
    public MyException(string msg, Exception inner) : base(msg, inner) { }
}
10
22.03.2017 13:10:47
это лучший ответ, потому что он также содержит перегрузки конструктора.
vibs2006 10.06.2018 02:56:13

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

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

или

public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject)
{
}
17
11.06.2018 10:47:32
Разве вам не нужно удалять слова «класс» из вашего примера, так как это конструкторы ...
MarzSocks 27.09.2016 04:50:43

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

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

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

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

public class MyException: Exception
{
    public MyException(string message, string extraInfo) : base($"{message} Extra info: {extraInfo}")
    {
    }
}
10
19.03.2019 06:31:07
@AndyMiddleditch Нет, это не так. Сеттер просто частный. docs.microsoft.com/en-us/dotnet/api/...
CShark 18.03.2019 16:01:25
@AndyMiddleditch Но вы правы, что предыдущая версия моего примера не скомпилируется из-за того, что атрибут сообщения имеет частный установщик. Я обновил свой пример, чтобы обойти это (теперь он будет компилироваться). Спасибо за хедз-ап.
CShark 19.03.2019 06:33:33

Используя новые возможности C #, а именно out var, вы можете избавиться от статического фабричного метода. Я только что обнаружил (случайно), что из параметра var методов, называемых "base base" - "call", перетекают в тело конструктора.

Пример использования этого базового класса, из которого вы хотите получить:

public abstract class BaseClass
{
    protected BaseClass(int a, int b, int c)
    {
    }
}

Некомпилируемый псевдокод, который вы хотите выполнить:

public class DerivedClass : BaseClass
{
    private readonly object fatData;

    public DerivedClass(int m)
    {
        var fd = new { A = 1 * m, B = 2 * m, C = 3 * m };
        base(fd.A, fd.B, fd.C); // base-constructor call
        this.fatData = fd;
    }
}

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

public class DerivedClass : BaseClass
{
    private readonly object fatData;

    public DerivedClass(int m)
        : base(PrepareBaseParameters(m, out var b, out var c, out var fatData), b, c)
    {
        this.fatData = fatData;
        Console.WriteLine(new { b, c, fatData }.ToString());
    }

    private static int PrepareBaseParameters(int m, out int b, out int c, out object fatData)
    {
        var fd = new { A = 1 * m, B = 2 * m, C = 3 * m };
        (b, c, fatData) = (fd.B, fd.C, fd); // Tuples not required but nice to use
        return fd.A;
    }
}
0
12.03.2020 15:37:45