Compartir a través de


Constructores de instancias (guía de programación de C#)

Se declara un constructor de instancia para especificar el código que se ejecuta al crear una nueva instancia de un tipo con la new expresión . Para inicializar una clase estática o variables estáticas en una clase no estática, puede definir un constructor estático.

Como se muestra en el ejemplo siguiente, puede declarar varios constructores de instancia en un tipo:

class Coords
{
    public Coords()
        : this(0, 0)
    {  }

    public Coords(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public override string ToString() => $"({X},{Y})";
}

class Example
{
    static void Main()
    {
        var p1 = new Coords();
        Console.WriteLine($"Coords #1 at {p1}");
        // Output: Coords #1 at (0,0)

        var p2 = new Coords(5, 3);
        Console.WriteLine($"Coords #2 at {p2}");
        // Output: Coords #2 at (5,3)
    }
}

En el ejemplo anterior, el primer constructor sin parámetros llama al segundo constructor con ambos argumentos igual a 0. Para ello, use la this palabra clave .

Al declarar un constructor de instancia en una clase derivada, puede llamar a un constructor de una clase base. Para ello, use la base palabra clave , como se muestra en el ejemplo siguiente:

abstract class Shape
{
    public const double pi = Math.PI;
    protected double x, y;

    public Shape(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public abstract double Area();
}

class Circle : Shape
{
    public Circle(double radius)
        : base(radius, 0)
    {  }

    public override double Area() => pi * x * x;
}

class Cylinder : Circle
{
    public Cylinder(double radius, double height)
        : base(radius)
    {
        y = height;
    }

    public override double Area() => (2 * base.Area()) + (2 * pi * x * y);
}

class Example
{
    static void Main()
    {
        double radius = 2.5;
        double height = 3.0;

        var ring = new Circle(radius);
        Console.WriteLine($"Area of the circle = {ring.Area():F2}");
        // Output: Area of the circle = 19.63
        
        var tube = new Cylinder(radius, height);
        Console.WriteLine($"Area of the cylinder = {tube.Area():F2}");
        // Output: Area of the cylinder = 86.39
    }
}

Constructores sin parámetros

Si una clase no tiene constructores de instancia explícitos, C# proporciona un constructor sin parámetros que puede usar para crear instancias de una instancia de esa clase, como se muestra en el ejemplo siguiente:

public class Person
{
    public int age;
    public string name = "unknown";
}

class Example
{
    static void Main()
    {
        var person = new Person();
        Console.WriteLine($"Name: {person.name}, Age: {person.age}");
        // Output:  Name: unknown, Age: 0
    }
}

Ese constructor inicializa los campos de instancia y las propiedades según los inicializadores correspondientes. Si un campo o propiedad no tiene inicializador, su valor se establece en el valor predeterminado del tipo de propiedad o del campo. Si declara al menos un constructor de instancia en una clase, C# no proporciona un constructor sin parámetros.

Un tipo de estructura siempre proporciona un constructor sin parámetros. El constructor sin parámetros es un constructor sin parámetros implícito que genera el valor predeterminado de un tipo o un constructor sin parámetros declarado explícitamente. Para obtener más información, consulte la sección Inicialización de estructura y valores predeterminados del artículo Tipos de estructura.

Constructores principales

A partir de C# 12, puede declarar un constructor principal en clases y estructuras. Los parámetros se colocan entre paréntesis siguiendo el nombre de tipo:

public class NamedItem(string name)
{
    public string Name => name;
}

Los parámetros de un constructor principal están dentro del ámbito de todo el cuerpo del tipo declarativo. Pueden inicializar propiedades o campos. Se pueden usar como variables en métodos o funciones locales. y pasarse a un constructor base.

Un constructor principal indica que estos parámetros son necesarios para cualquier instancia del tipo. Cualquier constructor escrito explícitamente debe usar la this(...) sintaxis del inicializador para invocar al constructor principal. Esto garantiza que todos los constructores asignan definitivamente los parámetros del constructor principal. Para cualquier class tipo, incluidos los tipos record class, el constructor sin parámetros implícito no se emite cuando existe un constructor principal. Para cualquier tipo struct, incluidos los tipos record struct, el constructor implícito sin parámetros siempre se emite y siempre inicializa todos los campos, incluidos los parámetros del constructor principal, al patrón de bits 0. Si escribe un constructor explícito sin parámetros, debe invocar el constructor principal. En ese caso, puede especificar un valor diferente para los parámetros del constructor principal. En el código siguiente se muestran ejemplos de constructores principales.

// name isn't captured in Widget.
// width, height, and depth are captured as private fields
public class Widget(string name, int width, int height, int depth) : NamedItem(name)
{
    public Widget() : this("N/A", 1,1,1) {} // unnamed unit cube

    public int WidthInCM => width;
    public int HeightInCM => height;
    public int DepthInCM => depth;

    public int Volume => width * height * depth;
}

Puede agregar atributos al método de constructor principal sintetizado especificando el method: destino en el atributo :

[method: MyAttribute]
public class TaggedWidget(string name)
{
   // details elided
}

Si no especifica el method destino, el atributo se coloca en la clase en lugar del método .

En los tipos class y struct, los parámetros del constructor principal están disponibles en cualquier parte del cuerpo del tipo. El parámetro se puede implementar como un campo privado capturado. Si las únicas referencias a un parámetro son inicializadores y llamadas de constructor, ese parámetro no se captura en un campo privado. Los usos en otros miembros del tipo hacen que el compilador capture el parámetro en un campo privado.

Si el tipo incluye el record modificador, el compilador sintetiza en su lugar una propiedad pública con el mismo nombre que el parámetro del constructor principal. Para record class los tipos, si un parámetro de constructor principal usa el mismo nombre que un constructor principal base, esa propiedad es una propiedad pública del tipo base record class . No se duplica en el tipo derivado record class. Estas propiedades no se generan para tipos no record.

Consulte también