Share via


Costruttori di istanze (Guida per programmatori C#)

Si dichiara un costruttore di istanza per specificare il codice eseguito quando si crea una nuova istanza di un tipo con l'espressionenew. Per inizializzare una classe statica o variabili statiche in una classe non statica , è possibile definire un costruttore statico.

Come illustrato nell'esempio seguente, è possibile dichiarare diversi costruttori di istanza in un solo 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)
    }
}

Nell'esempio precedente, il primo costruttore senza parametri chiama il secondo costruttore con entrambi gli argomenti uguali 0a . A tale scopo, usare la this parola chiave .

Quando si dichiara un costruttore di istanza in una classe derivata, è possibile chiamare un costruttore di una classe base. A tale scopo, usare la base parola chiave , come illustrato nell'esempio seguente:

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

Costruttori senza parametri

Se una classe non dispone di costruttori di istanze espliciti, C# fornisce un costruttore senza parametri che è possibile usare per creare un'istanza di tale classe, come illustrato nell'esempio seguente:

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

Tale costruttore inizializza i campi e le proprietà dell'istanza in base agli inizializzatori corrispondenti. Se un campo o una proprietà non dispone di inizializzatore, il relativo valore viene impostato sul valore predefinito del tipo del campo o della proprietà. Se si dichiara almeno un costruttore di istanza in una classe, C# non fornisce un costruttore senza parametri.

Un tipo di struttura fornisce sempre un costruttore senza parametri. Il costruttore senza parametri è un costruttore senza parametri implicito che produce il valore predefinito di un tipo o un costruttore senza parametri dichiarato in modo esplicito. Per altre informazioni, vedere la sezione Inizializzazione Struct e valori predefiniti dell'articolo Tipi di struttura.

Costruttori primari

A partire da C# 12, è possibile dichiarare un costruttore primario in classi e struct. Tutti i parametri vengono inseriti tra parentesi dopo il nome del tipo:

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

I parametri di un costruttore primario sono inclusi nell'ambito nell'intero corpo del tipo dichiarante. Possono inizializzare proprietà o campi. Possono essere usati come variabili nei metodi o nelle funzioni locali. Possono essere passati a un costruttore di base.

Un costruttore primario indica che questi parametri sono necessari per qualsiasi istanza del tipo. Qualsiasi costruttore scritto in modo esplicito deve usare la sintassi dell'inizializzatore this(...) per richiamare il costruttore primario. Ciò garantisce che i parametri del costruttore primario siano sicuramente assegnati da tutti i costruttori. Per qualsiasi class tipo, inclusi record class i tipi, il costruttore implicito senza parametri non viene generato quando è presente un costruttore primario. Per qualsiasi struct tipo, inclusi record struct i tipi, il costruttore implicito senza parametri viene sempre generato e inizializza sempre tutti i campi, inclusi i parametri del costruttore primario, al modello a 0 bit. Se si scrive un costruttore esplicito senza parametri, deve richiamare il costruttore primario. In tal caso, è possibile specificare un valore diverso per i parametri del costruttore primario. Il codice seguente mostra esempi di costruttori primari.

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

È possibile aggiungere attributi al metodo del costruttore primario sintetizzato specificando la method: destinazione nell'attributo :

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

Se non si specifica la method destinazione, l'attributo viene inserito nella classe anziché nel metodo .

In class e struct i parametri del costruttore primario sono disponibili in qualsiasi punto del corpo del tipo. Possono essere usati come campi membro. Quando si usa un parametro del costruttore primario, il compilatore acquisisce il parametro del costruttore in un campo privato con un nome generato dal compilatore. Se un parametro del costruttore primario non viene usato nel corpo del tipo, non viene acquisito alcun campo privato. Questa regola impedisce di allocare accidentalmente due copie di un parametro del costruttore primario passato a un costruttore di base.

Se il tipo include il record modificatore, il compilatore sintetizza invece una proprietà pubblica con lo stesso nome del parametro del costruttore primario. Per record class i tipi, se un parametro del costruttore primario utilizza lo stesso nome di un costruttore primario di base, tale proprietà è una proprietà pubblica del tipo di base record class . Non viene duplicato nel tipo derivato record class . Queste proprietà non vengono generate perrecord i tipi non.

Vedi anche