Partilhar via


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

Você declara um construtor de instância para especificar o código que é executado quando você cria 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, sem parâmetros, chama o segundo construtor com ambos os argumentos iguais 0. Para fazer isso, use a this palavra-chave.

Quando você declara 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 campos de instância e propriedades de acordo com os inicializadores correspondentes. Se um campo ou propriedade não tiver inicializador, seu valor será definido como o valor padrão do tipo de campo ou propriedade. Se você declarar pelo menos um construtor de instância em uma classe, 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 sem parâmetros explicitamente declarado. Para obter mais informações, consulte a seção Inicialização de struct e valores padrão do artigo Tipos de estrutura.

Construtores primários

A partir de C# 12, você pode declarar um construtor primário em classes e structs. Coloque todos os parâmetros entre parênteses após 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 declarante. Eles podem inicializar propriedades ou campos. Eles podem ser usados como variáveis em métodos ou funções locais. Eles podem ser passados para um construtor de base.

Um construtor primário indica que esses parâmetros são necessários para qualquer instância do tipo. Qualquer construtor explicitamente escrito deve usar a sintaxe do this(...) inicializador para invocar o construtor primário. Isso garante que os parâmetros primários do construtor 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 struct tipo, incluindo record struct tipos, o construtor implícito sem parâmetros é sempre emitido e sempre inicializa todos os campos, incluindo os parâmetros primários do construtor, para o padrão de 0 bits. Se você escrever um construtor sem parâmetros explícito, ele deve invocar o construtor primário. Nesse caso, você pode especificar um valor diferente para os parâmetros primários do construtor. 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.

Em class e struct tipos, os parâmetros primários do construtor 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. Usos em outros membros do tipo fazem com que o compilador capture o parâmetro em um campo privado.

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

Consulte também