Creare costruttori di classi e creare istanze di oggetti
Oltre alle proprietà e ai metodi della classe, le definizioni di classe includono costruttori usati per inizializzare nuovi oggetti (istanze di classe).
Costruttori di classi
Un costruttore di classe è un metodo con lo stesso nome del tipo (i metodi del costruttore usano lo stesso nome della classe).
Esistono due tipi di costruttori di classi:
- Costruttori di istanze. I costruttori di istanza vengono usati per creare e inizializzare le variabili di campo dell'istanza quando viene creato un oggetto.
- Costruttori statici. I costruttori statici vengono usati per inizializzare i dati statici o per eseguire una determinata azione che deve essere eseguita una sola volta. I costruttori statici vengono chiamati automaticamente prima della creazione della prima istanza o di tutti i membri statici a cui viene fatto riferimento.
I costruttori di classi sono costruttori di istanza per impostazione predefinita.
Sintassi del costruttore dell'istanza
Un costruttore di istanza viene dichiarato usando lo stesso nome della classe e non include un tipo restituito. La firma del metodo del costruttore può includere un modificatore di accesso facoltativo, il nome del metodo e il relativo elenco di parametri. Le firme del metodo di un costruttore non includono un tipo restituito.
L'esempio seguente mostra un costruttore semplice per una classe denominata Person:
public class Person
{
public Person()
{
// Field initialization and constructor logic goes here.
}
// Remaining implementation of Person class.
}
Le classi possono avere più costruttori. Quando una classe ha più di un costruttore, i costruttori in genere accettano argomenti diversi.
Nell'esempio seguente viene illustrata una classe denominata Person con due costruttori.
public class Person
{
public Person()
{
// Field initialization and constructor logic goes here.
string name = "Person One";
Console.WriteLine($"Person created: {name}");
}
public Person(string fName, string lName)
{
string name = fName + " " + lName;
Console.WriteLine($"Person created: {name}");
}
// Remaining implementation of Person class.
}
Creare un'istanza di oggetti usando costruttori di classi
Quando viene creata un'istanza di un oggetto usando la parola chiave new, il runtime .NET chiama il costruttore di istanza associato nella definizione della classe e alloca la memoria per l'oggetto.
Nel frammento di codice seguente la classe Person definisce un costruttore di istanza semplice. La classe Program include un metodo Main che usa l'operatore new per creare un'istanza di Person denominata person1. Il runtime richiama il costruttore Person immediatamente dopo l'allocazione della memoria per il nuovo oggetto.
public class Person
{
public Person()
{
// Field initialization and constructor logic goes here.
}
}
static class Program
{
// the Main method is the entry point of the program.
static void Main()
{
Person person1 = new Person();
}
}
Costruttori con e senza parametri
Un costruttore che non accetta parametri viene chiamato costruttore senza parametri. Il runtime richiama il costruttore senza parametri quando viene creata un'istanza di un oggetto usando l'operatore new e non vengono forniti argomenti al costruttore.
Nota
A meno che la classe non sia statica, alle classi senza costruttori viene assegnato un costruttore pubblico senza parametri dal compilatore C# per abilitare la creazione di istanze della classe.
Le classi spesso definiscono costruttori che accettano parametri. I costruttori che accettano parametri devono essere chiamati usando l'operatore new o un'istruzione base. Le classi possono definire uno o più costruttori.
Il frammento di codice seguente mostra una classe denominata Person con tre costruttori:
public class Person
{
public Person()
{
// Field initialization and constructor logic goes here.
Console.WriteLine("An instance of the Person class is being instantiated without name or age parameters.");
}
public Person(string name)
{
// Field initialization and constructor logic goes here.
Console.WriteLine($"An instance of the Person class is being instantiated using a name ({name}) parameter.");
}
public Person(string name, int age)
{
// Field initialization and constructor logic goes here.
Console.WriteLine($"An instance of the Person class is being instantiated using name ({name}) and age ({age}) parameters.");
}
}
static class Program
{
// the Main method is the entry point of the program.
static void Main()
{
Person person1 = new Person();
Person person2 = new Person("Person Two");
Person person3 = new Person("Person Three", 30);
}
}
Classi senza costruttori
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
}
}
Questo 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.
Inizializzare i dati della classe usando i parametri del costruttore
I parametri passati a un costruttore sono locali al costruttore. I parametri vengono spesso usati per inizializzare i campi dati di una classe.
Il frammento di codice seguente mostra una classe denominata Person con costruttori che inizializzano i campi personName e personAge:
public class Person
{
public string personName;
public string personAge;
public Person()
{
// Field initialization and constructor logic goes here.
personName = "unknown";
personAge = "unknown";
}
public Person(string name)
{
// Field initialization and constructor logic goes here.
personName = name;
personAge = "unknown";
}
public Person(string name, int age)
{
// Field initialization and constructor logic goes here.
personName = name;
personAge = age.ToString();
}
}
static class Program
{
// the Main method is the entry point of the program.
static void Main()
{
Person person1 = new Person();
Person person2 = new Person("Person Two");
Person person3 = new Person("Person Three", 30);
Console.WriteLine($"Person 1 Name: {person1.personName} Age: {person1.personAge}");
Console.WriteLine($"Person 2 Name: {person2.personName} Age: {person2.personAge}");
Console.WriteLine($"Person 3 Name: {person3.personName} Age: {person3.personAge}");
}
}
Nell'esempio precedente la classe Person viene definita con tre costruttori. Il primo costruttore inizializza i campi personName e personAge per "unknown". Il secondo costruttore inizializza il campo personName sul valore passato nel parametro name e il campo personAge per "unknown". Il terzo costruttore inizializza rispettivamente i campi personName e personAge ai valori passati rispettivamente nei parametri name e age.
Poiché i campi sono pubblici, è possibile accedervi direttamente dal metodo Main. Quando viene eseguito il codice, viene generato l'output seguente:
Person 1 Name: unknown Age: unknown
Person 2 Name: Person Two Age: unknown
Person 3 Name: Person Three Age: 30
Definizioni del corpo dell'espressione
Se un costruttore può essere implementato come singola istruzione, è possibile usare una definizione del corpo dell'espressione per assegnare un parametro a un membro della classe quando viene implementato il costruttore.
Ad esempio, il costruttore seguente inizializza il campo modelName con il valore passato al parametro model:
public class Car
{
public string modelName;
public Car(string model) => modelName = model;
}
La classe Car ha un singolo campo pubblico, modelName, che è di tipo string. Il campo modelName è destinato a memorizzare il nome del modello di auto.
La classe Car include anche un costruttore che accetta un singolo parametro stringa denominato model. Il costruttore usa una definizione del corpo dell'espressione (indicata dalla sintassi =>) per inizializzare il campo modelName con il valore passato al parametro model. Ciò significa che quando viene creata un'istanza di un nuovo oggetto Car, il campo modelName viene impostato sul valore fornito come argomento per il costruttore.
Poiché il termine 'espressione implica, il lato destro dell'operatore => è un'espressione e non è limitata a un'istruzione di assegnazione semplice. L'espressione può essere qualsiasi espressione C# valida che restituisce un valore.
Il frammento di codice seguente illustra come implementare una definizione del corpo dell'espressione che esegue un calcolo semplice:
public class Employee
{
public int Salary;
public Employee() { }
public Employee(int annualSalary) => Salary = annualSalary;
public Employee(int weeklySalary, int numberOfWeeks) => Salary = weeklySalary * numberOfWeeks;
}
Questa classe può essere creata usando una delle istruzioni seguenti:
Employee e1 = new Employee(30000);
Employee e2 = new Employee(500, 52);
Costruttori statici
Un costruttore statico viene usato per inizializzare tutti i dati statici o per eseguire una determinata azione che deve essere eseguita una sola volta. Viene chiamato automaticamente prima della creazione della prima istanza o viene fatto riferimento a tutti i membri statici. Un costruttore statico viene chiamato al massimo una volta.
Il frammento di codice seguente mostra una versione aggiornata della classe Person che implementa campi statici e un costruttore statico:
public class Person
{
public string personName;
public string personAge;
// Static field
public static string defaultName;
public static string defaultAge;
// Static constructor
static Person()
{
// Static field initialization
defaultName = "unknown";
defaultAge = "unknown";
}
public Person()
{
// Field initialization and constructor logic goes here.
personName = defaultName;
personAge = defaultAge;
}
public Person(string name)
{
// Field initialization and constructor logic goes here.
personName = name;
personAge = defaultAge;
}
public Person(string name, int age)
{
// Field initialization and constructor logic goes here.
personName = name;
personAge = age.ToString();
}
}
La classe Person aggiornata include due campi di istanza, personName e personAge, entrambi di tipo string. Questi campi archiviano rispettivamente il nome e l'età di una persona.
La classe definisce anche due campi statici, defaultName e defaultAge, anche di tipo string. I campi statici vengono condivisi tra tutte le istanze della classe e vengono inizializzati una sola volta. In questo caso, i campi statici vengono usati per fornire valori predefiniti per i campi personName e personAge.
Il costruttore statico static Person() è responsabile dell'inizializzazione dei campi statici. Imposta defaultName su "unknown" e defaultAge su "unknown". Il costruttore statico viene chiamato automaticamente prima della creazione di qualsiasi istanza della classe o di tutti i membri statici.
La classe Person include tre costruttori di istanza:
Il costruttore senza parametri public Person() inizializza i campi personName e personAge con i valori dei campi statici defaultName e defaultAge. Ciò significa che se non vengono forniti argomenti durante la creazione di un oggetto Person, i valori predefiniti "unknown" vengono usati sia per il nome che per l'età.
Il costruttore public Person(string name) accetta un singolo parametro, namee inizializza il campo personName con questo valore. Il campo personAge viene inizializzato con il valore del campo statico defaultAge. Questo costruttore consente la creazione di un oggetto Person con un nome specificato durante l'utilizzo dell'età predefinita.
Il costruttore public Person(string name, int age) accetta due parametri, name e age. Inizializza il campo personName con il valore del parametro name e il campo personAge con la rappresentazione di stringa del parametro age. Questo costruttore consente la creazione di un oggetto Person con un name specificato e age.
Proprietà dei costruttori statici
I costruttori statici hanno le proprietà seguenti:
Un costruttore statico non accetta modificatori di accesso o ha parametri.
Una classe può avere un solo costruttore statico.
I costruttori statici non possono essere ereditati o sovraccaricati.
Un costruttore statico non può essere chiamato direttamente ed è destinato solo a essere chiamato da Common Language Runtime (CLR). Viene richiamato automaticamente.
L'utente non ha alcun controllo su quando il costruttore statico viene eseguito nel programma.
Un costruttore statico viene chiamato automaticamente. Inizializza la classe prima della creazione della prima istanza o i membri statici dichiarati in tale classe (non le relative classi di base). Un costruttore statico viene eseguito prima di un costruttore di istanza. Se gli inizializzatori di variabili di campo statici sono presenti nella classe del costruttore statico, vengono eseguiti nell'ordine testuale in cui vengono visualizzati nella dichiarazione di classe. Gli inizializzatori vengono eseguiti immediatamente prima del costruttore statico.
Se non si fornisce un costruttore statico per inizializzare i campi statici, tutti i campi statici vengono inizializzati sul valore predefinito.
Se un costruttore statico genera un'eccezione, il runtime non lo richiama una seconda volta e il tipo rimane non inizializzato per la durata del dominio applicazione. In genere, viene generata un'eccezione
TypeInitializationExceptionquando un costruttore statico non è in grado di creare un'istanza di un tipo o di un'eccezione non gestita che si verifica all'interno di un costruttore statico. Per i costruttori statici che non sono definiti in modo esplicito nel codice sorgente, la risoluzione dei problemi potrebbe richiedere l'ispezione del codice DEL (Intermediate Language).La presenza di un costruttore statico impedisce l'aggiunta dell'attributo di tipo
BeforeFieldInit. Questo limita l'ottimizzazione del runtime.Un campo dichiarato come
static readonlypuò essere assegnato solo come parte della relativa dichiarazione o in un costruttore statico. Quando non è necessario un costruttore statico esplicito, inizializzare campi statici in corrispondenza della dichiarazione anziché tramite un costruttore statico per migliorare l'ottimizzazione del runtime.Il runtime chiama un costruttore statico non più di una volta in un singolo dominio applicazione. Tale chiamata viene eseguita in un'area bloccata in base al tipo specifico della classe. Non sono necessari meccanismi di blocco aggiuntivi nel corpo di un costruttore statico.
Nota
Anche se non è direttamente accessibile, la presenza di un costruttore statico esplicito deve essere documentata per facilitare la risoluzione dei problemi relativi alle eccezioni di inizializzazione.