Compartilhar via


Construtores de instância (guia de programação em C#)

Você declara um construtor de instância para especificar o código executado ao criar uma nova instância de um tipo com a new expressão. Para inicializar uma classe estática ou variáveis estáticas em uma classe não estática, você pode definir um construtor estático.

Como mostra o exemplo a seguir, você pode declarar vários construtores de instância em um 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)
    }
}

No exemplo anterior, o primeiro construtor, sem parâmetros, chama o segundo construtor com ambos os argumentos iguais 0. Para fazer isso, use a this palavra-chave.

Ao declarar um construtor de instância em uma classe derivada, você pode chamar um construtor de uma classe base. Para fazer isso, use a base palavra-chave, como mostra o exemplo a seguir:

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

Construtores sem parâmetros

Se uma classe não tiver construtores de instância explícitos, o C# fornecerá um construtor sem parâmetros que você pode usar para instanciar uma instância dessa classe, como mostra o exemplo a seguir:

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

Esse construtor inicializa os campos e as propriedades da instância de acordo com os inicializadores correspondentes. Se um campo ou propriedade não tiver um inicializador, seu valor será definido como o valor padrão do tipo do campo ou da propriedade. Se você declarar pelo menos um construtor de instância em uma classe, o C# não fornecerá um construtor sem parâmetros.

Um tipo de estrutura sempre fornece um construtor sem parâmetros. O construtor sem parâmetros é um construtor implícito sem parâmetros que produz o valor padrão de um tipo ou um construtor explicitamente declarado sem parâmetros. Para obter mais informações, consulte a seção inicialização do Struct e valores padrão do artigo Tipos de estrutura .

Construtores primários

A partir do C# 12, você pode declarar um construtor primário em classes e structs. Você coloca todos os parâmetros entre parênteses seguindo o nome do tipo:

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

Os parâmetros para um construtor primário estão no escopo em todo o corpo do tipo de declaração. Eles podem inicializar propriedades ou campos. Elas podem ser usadas como variáveis em métodos ou funções locais. Eles podem ser passados para um construtor base.

Um construtor primário indica que esses parâmetros são necessários para qualquer instância do tipo. Qualquer construtor escrito explicitamente deve usar a sintaxe do this(...) inicializador para invocar o construtor primário. Isso garante que os parâmetros do construtor primário sejam definitivamente atribuídos por todos os construtores. Para qualquer class tipo, incluindo record class tipos, o construtor implícito sem parâmetros não é emitido quando um construtor primário está presente. Para qualquer tipo struct, incluindo tipos record struct, o construtor implícito sem parâmetros é sempre emitido e inicializa todos os campos, incluindo os parâmetros do construtor primário, com o padrão de bits 0. Se você escrever um construtor sem parâmetros explícito, ele deverá invocar o construtor primário. Nesse caso, você pode especificar um valor diferente para os parâmetros do construtor primário. O código a seguir mostra exemplos de construtores primários.

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

Você pode adicionar atributos ao método de construtor primário sintetizado especificando o method: destino no atributo:

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

Se você não especificar o method destino, o atributo será colocado na classe em vez do método.

Nos tipos class e struct, os parâmetros do construtor principal estão disponíveis em qualquer lugar no corpo do tipo. O parâmetro pode ser implementado como um campo privado capturado. Se as únicas referências a um parâmetro forem inicializadores e chamadas de construtor, esse parâmetro não será capturado em um campo privado. Os usos em outros membros do tipo fazem com que o compilador capture o parâmetro em um campo privado.

Se o tipo incluir o modificador record, o compilador sintetizará uma propriedade pública com o mesmo nome que o parâmetro do construtor primário. Para tipos record class, se um parâmetro de construtor primário tiver o mesmo nome de um construtor primário base, essa propriedade é pública no tipo base record class. Ele não é duplicado no tipo derivado record class. Essas propriedades não são geradas para tipos que não sejam record.

Consulte também