Llamar al constructor base en C #

Si heredo de una clase base y quiero pasar algo del constructor de la clase heredada al constructor de la clase base, ¿cómo lo hago?

Por ejemplo, si heredo de la clase Exception, quiero hacer algo como esto:

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

Básicamente, lo que quiero es poder pasar el mensaje de cadena a la clase de excepción base.

preguntado el 15 de agosto de 08 a las 05:08

También vale la pena señalar que puede encadenar constructores en su clase actual sustituyendo this para base. -

En lugar de decir "todo se está derrumbando", es mucho más útil publicar el error que está recibiendo.

12 Respuestas

Modifique su constructor a lo siguiente para que llame correctamente al constructor de la clase base:

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

Tenga en cuenta que un constructor no es algo a lo que pueda llamar en cualquier momento dentro de un método. Esa es la razón por la que está recibiendo errores en su llamada en el cuerpo del constructor.

Respondido 15 ago 08, 08:08

Creo que puede haber perdido el punto. El problema era llamar a un constructor base a la mitad del constructor anulado. Quizás el tipo de datos del constructor base no sea el mismo o desee hacer un modelado de datos antes de pasarlo por la cadena. ¿Cómo lograrías tal hazaña? - Marchy

Si necesita llamar al constructor base en medio de la anulación, extráigalo a un método real en la clase base que pueda llamar explícitamente. La suposición con los constructores base es que son absolutamente necesarios para crear un objeto de forma segura, por lo que la base se llamará primero, siempre. - jon limjap

It is solo un método al que puede llamar en cualquier momento, en cuanto a IL. C # simplemente pone restricciones adicionales además de esto. - romano starkov

Vale la pena señalar que el base se llama constructor antes se accede al bloque de método. msdn.microsoft.com/en-us/library/ms173115.aspx - Juan Weisz

No es un buen diseño si necesita llamar al constructor de la clase base a mitad de camino durante su constructor. La idea de un constructor es que hace todo el trabajo necesario para realizar su tarea. Esto tiene el efecto de que cuando se inicia su constructor derivado, la clase base ya está completamente inicializada y la clase derivada es libre de llamar a cualquier función de clase base. Si su diseño es tal que desea hacer algo a mitad de camino con su constructor, entonces aparentemente esto no está inicializando la clase base y, por lo tanto, no debería estar en el constructor de la clase base sino en una función separada, posiblemente protegida - harald coppoolse

Tenga en cuenta que puede usar estático métodos dentro de la llamada al constructor base.

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;
     }
}

Respondido 31 ago 15, 18:08

La clase Exception está tan bloqueada que me encuentro haciendo esto un par de veces, pero también tenga en cuenta que no es algo que deba hacer si puede evitarlo. - Jonathan Cwik

Lo siento, C # newb aquí. ¿Por qué llamas? Trace.WriteLine("message was " + message)? - kdbanman

@kdbanman Eso solo genera un mensaje de depuración. Sin propósito funcional relevante. - Nick Whaley

Gran respuesta. Respuesta aceptada no me permite procesar; y el comentario de seguimiento sobre una solución alternativa asume que tengo acceso para cambiar la clase base; Yo no. Una respuesta de fábrica asume que puedo controlar cómo se crea una instancia de la clase; No puedo. Solo tu respuesta me permite modificar algo antes de pasarlo a la base. - El guisante rojo

Si se encuentra en la situación descrita anteriormente. En lugar de herencia, puede construir su clase como un contenedor de la clase base como una solución alternativa. - No hacer

Si necesita llamar al constructor base pero no de inmediato porque su nueva clase (derivada) necesita realizar alguna manipulación de datos, la mejor solución es recurrir al método de fábrica. Lo que debe hacer es marcar como privado su constructor derivado, luego crear un método estático en su clase que hará todo lo necesario y luego llamar al constructor y devolver el objeto.

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);
    }
}

Respondido 07 Abr '13, 21:04

Esto podría la posibilidad viola los principios SÓLIDOS (SRP), porque la responsabilidad de crear la clase está encapsulada con cualquier otra responsabilidad de la que se suponía que debía ocuparse la clase. Se podría usar una fábrica abstracta, pero podría agregar una complejidad innecesaria al código simple. Por supuesto, la violación de los SÓLIDOS está bien si conoce la compensación y el costo que supondrá para su arquitectura (y cómo solucionar cualquier problema futuro que pueda surgir de su decisión de diseño). - Sebastien

Es cierto que usa el base (algo) para llamar al constructor de la clase base, pero en caso de sobrecarga use el this keyword

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

Respondido 09 Abr '18, 12:04

Veo lo que intentas explicar y tienes razón. Si tiene dos constructores en una clase, puede hacer referencia a uno del otro usando la palabra clave "this" de manera similar a como usa "base" cuando llama al constructor heredado. Sin embargo, esto no es lo que pidió el OP, por lo que este no es realmente el lugar para agregar esto. - soyTimCorey

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

Puede pasar la excepción interna a uno de los constructores.

Respondido el 04 de diciembre de 09 a las 05:12

Desde Pautas de diseño del marco y reglas de FxCop.:

1. La excepción personalizada debe tener un nombre que termine en Exception

    class MyException : Exception

2. La excepción debe ser pública

    public class MyException : Exception

3. CA1032: La excepción debería implementar constructores estándar.

  • Un constructor público sin parámetros.
  • Un constructor público con un argumento de cadena.
  • Un constructor público con una cadena y una excepción (ya que puede envolver otra excepción).
  • Un constructor de serialización protegido si el tipo no está sellado y privado si el tipo está sellado. Residencia en 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.
      }
    }  
    

or

    [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.
      }
    }  

Respondido el 24 de enero de 16 a las 07:01

También puede hacer una verificación condicional con parámetros en el constructor, lo que permite cierta flexibilidad.

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

or

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

Respondido el 11 de junio de 18 a las 11:06

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

respondido 22 mar '17, 13:03

esta es la mejor respuesta porque también contiene sobrecargas de constructores. - vibraciones2006

Según algunas de las otras respuestas enumeradas aquí, puede pasar parámetros al constructor de la clase base. Se recomienda llamar al constructor de su clase base al comienzo del constructor para su clase heredada.

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

Observo que en su ejemplo nunca hizo uso de la extraInfo parámetro, así que asumí que es posible que desee concatenar el extraInfo parámetro de cadena al Message propiedad de su excepción (parece que esto se ignora en la respuesta aceptada y el código en su pregunta).

Esto se logra simplemente invocando el constructor de la clase base y luego actualizando la propiedad Message con la información adicional.

public class MyException: Exception
{
    public MyException(string message, string extraInfo) : base($"{message} Extra info: {extraInfo}")
    {
    }
}

respondido 19 mar '19, 06:03

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

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

Respondido 26 Feb 15, 04:02

Usando las características más nuevas de C #, a saber out var, puede deshacerse del método de fábrica estático. Acabo de descubrir (por accidente) que el parámetro var de los métodos llamados inse base- "call" fluye hacia el cuerpo del constructor.

Ejemplo, usando esta clase base de la que desea derivar:

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

El pseudocódigo no compilable que desea ejecutar:

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;
    }
}

Y la solución mediante el uso de un método auxiliar privado estático que produce todos los argumentos base requeridos (más datos adicionales si es necesario) y sin usar un método de fábrica estático, simplemente constructor simple hacia el exterior:

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;
    }
}

respondido 12 mar '20, 15:03

public class Car
{
     public Car(string model)
     {
        Console.WriteLine(model);
     }
}

public class Mercedes : Car
{
     public Mercedes(string model): base(model)
     {

     }
}

Uso:

Mercedes mercedes = new Mercedes("CLA Shooting Brake");

Salida: CLA Shooting Brake

contestado el 25 de mayo de 20 a las 11:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.