Gerarchia di Costruttori in C#

In questa breve panoramica, voglio illustrare il concetto di Gerarchia di costruttori così come interpretata da C# confrontandola con Java.

Consideriamo ad esempio le classi Persona e Manager: Persona è superclasse di Manager.

In Java il costruttore per Manager è strutturato di default in questo modo:

[java]
public Manager(){
super();
}
[/java]

Dove super sarà il costruttore di default di Persona, questo comporta che se la classe Persona non ha il costruttore di default allora avremo un errore in compilazione.

Pertanto assumiamo che la classe Persona definisca il costruttore che segue:

[java]
public Persona(String nome, String cognome) {
this.nome=nome;
this.cognome=cognome;
}[/java]

Dobbiamo modificare il costruttore di senza parametri Manager:

[java]
public Manager(){
super("cognome","nome");
}[/java]

Volendo essere più puliti, aggiungiamo un costruttore parametrico.

[java] public Manager(String cognome, String nome){
super(cognome,nome);
}[/java]

Ricordiamo che la prima istruzione del nuovo costruttore dev’essere la chiamata al costruttore della superclasse.
A questo punto ci poniamo una domanda: Come chiamiamo un’altro costruttore della stessa classe?

Ovvero come possiamo chiamare Manager(String cognome, String nome) da Manager()?

Utilizzeremo la keyword this, che in questo caso assume un significato diverso dal normale riferimento implicito all’oggetto.

[java] public Manager(String cognome, String nome){
this();
this.cognome=cognome;
this.nome=nome;
}[/java]

In java abbiamo più comportamenti ambigui:

La chiamata al costruttore deve essere la prima istruzione del costruttore, non sono ammesse più chiamate a più costruttori. Non aspettatevi chiamate del tipo:

[java] public Manager(String cognome, String nome){
this();
this(nome,cognome,indirizzo) //errore di compilazione.
this.cognome=cognome;
this.nome=nome;
}[/java]

Alla riga 3 avremo errore di compilazione.

In C# il concetto resta il medesimo, cambia in modo rilevante la sintassi che impedisce di fatto di avere errori di compilazione come visto nell’ultimo esempio.

La tecnica è questa: Il costruttore da richiamare non viene inserito come prima istruzione del costruttore stesso, ma come suffisso all’istruzione che dichiara il costruttore.

[csharp]public Persona():this("Nome","Cognome")
{
System.Console.WriteLine("Persona");
}

public Persona(String nome, String cognome)
{
System.Console.WriteLine("Persona più parametri");
}
[/csharp]

L’output in questo caso sarà:

Persona più parametri

Persona

Identico al comportamento di Java.

Se si vuole chiamare un particolare costruttore della superclasse bisognerà utilizzare la keyword “base” (in java abbiamo visto che è “super“).

[csharp]
public Manager():base("nome","cognome")
{
System.Console.WriteLine("Manager");
}

[/csharp]

La differenza tra i due linguaggi può sembrar “effimera”, tuttavia bisogna osservare che in effetti in Java la chiamata ad un altro costruttore non passa facilmente in secondo piano, avendo a tutti gli effetti dignità di istruzione.
Mentre in C# viene vista, in un certo senso, come una “aggiunta” al costruttore, appesantendone la sintassi e rendendo macchinosa e non immediata la comprensione, specialmente nel caso in cui ci siano molti parametri nel costruttore.

ad esempio, in java:

[java] public Manager(String nome){
this(nome,"Cognome");
}

public Manager(String nome, String Cognome){
this.nome= nome;
this.cognome = cognome;
}
[/java]

Mentre in C# avremo:

[csharp]
public Manager(String nome):base(nome,"cognome")
{ }
public Manager(String nome, String cognome){
this.nome= nome;
this.cognome = cognome;
}
[/csharp]

Per concludere, in C# abbiamo una sintassi orientata ad evitare errori in compilazione,
in Java si vuole che sia chiara e immediata la comprensione del fatto che si utilizza un gerarchia di costruttori.