Overload dei Metodi in C#

A volte, potrebbe essere necessario creare più metodi che differiscono per il tipo o il numero dei parametri.

Una possibile soluzione è quella di creare metodi con nomi differenti, ma questo può rendere il codice più difficile da leggere e manutenere.

In C#, possiamo creare più metodi con lo stesso nome ma firme diverse. Questa tecnica prende il nome di Overload o Sovraccarico dei metodi.

Attraverso l'overload dei metodi, lasciamo al compilatore C# il compito di determinare quale metodo chiamare in base al tipo di parametro passato.

Sovraccarico dei Metodi

Quando viene dichiarato un metodo e il suo nome coincide con il nome di un altro metodo, ma le loro firme differiscono per la lista dei parametri (numero dei parametri del metodo o il modo in cui sono disposti), si dice che ci sono diverse varianti o sovraccarichi di quel metodo (overload dei metodi).

Ad esempio, supponiamo di dover scrivere un programma che disegna lettere e cifre sullo schermo. Possiamo anche supporre che il nostro programma abbia metodi per disegnare stringhe DisegnaStringa(string str), interi DisegnaIntero(int numero), e numeri in virgola mobile DisegnaFloat(float numero) e così via:

static void DisegnaStringa(string str)
{
    // Disegna stringa
}

static void DisegnaIntero(int numero)
{
    // Disegna intero
}
static void DisegnaFloat(float numero)
{
    // Disegna numero a virgola mobile
}

Questa tecnica di realizzare un metodo differente per ogni tipo di parametro è particolarmente onerosa e soggetta ad errori. Inoltre, se vogliamo disegnare un numero intero, dobbiamo chiamare il metodo DisegnaIntero(int numero), e se vogliamo disegnare un numero a virgola mobile, dobbiamo chiamare il metodo DisegnaFloat(float numero). Questo è un po' scomodo, perché dobbiamo ricordare quale metodo chiamare per quale tipo di parametro.

Invece, possiamo creare più metodi con lo stesso nome ma con firme diverse, ossia che accettano diversi tipi di parametri. Ad esempio, possiamo creare i seguenti metodi:

static void Disegna(string str)
{
    // Disegna stringa
}

static void Disegna(int numero)
{
    // Disegna intero
}

static void Disegna(float numero)
{
    // Disegna numero a virgola mobile
}

Questa tecnica prende il nome di Overload o Sovraccarico dei metodi. In questo caso, abbiamo tre metodi con lo stesso nome Disegna, ma con firme diverse. Ogni metodo accetta un tipo di parametro diverso. Quando chiamiamo il metodo Disegna, il compilatore C# determina quale metodo chiamare in base al tipo di parametro passato. Non abbiamo più bisogno di ricordare quale metodo chiamare per quale tipo di parametro:

// Chiamiamo la versione del metodo Disegna che accetta una stringa
Disegna("Hello, World!");

// Chiamiamo la versione del metodo Disegna che accetta un intero
Disegna(42);

// Chiamiamo la versione del metodo Disegna che accetta un numero a virgola mobile
Disegna(3.14f);
Definizione

Sovraccarico o Overload dei Metodi

L'Overload o Sovraccarico dei metodi è una tecnica che consente di creare più metodi con lo stesso nome ma con firme diverse.

In fase di invocazione, il compilatore C# determina quale metodo chiamare in base al tipo di parametro passato.

Parametri del Metodo e Firma del Metodo

Come accennato in precedenza, ci sono solo tre cose richieste in C# per specificare una firma di metodo:

  1. Il nome del metodo;
  2. I tipi dei parametri;
  3. L'ordine con cui i tipi dei parametri sono elencati.

Viceversa, due elementi non sono significativi per la firma di un metodo:

  1. Il nome dei parametri;
  2. Il tipo di ritorno del metodo.

L'aspetto più importante della creazione di una dichiarazione non ambigua di un metodo in C# è la definizione della sua firma e in particolare il tipo dei parametri del metodo.

Ad esempio, in C#, le seguenti due dichiarazioni sono in realtà dichiarazioni dello stesso metodo. Questo perché il tipo di parametro in ciascuno dei loro parametri è lo stesso: int e float.

// Queste due righe causeranno un errore
static void Esempio(int param1, float param2) { }
static void Esempio(int p1, float p2) { }

Quindi i nomi delle variabili che stiamo usando, param1 e param2 o p1 e p2, non sono significativi: il compilatore C# non li considera nella firma del metodo.

Se dichiariamo due o più metodi, nel modo mostrato sopra, il compilatore mostrerà un messaggio di errore, che sarà simile a quello riportato di seguito:

error CS0128: A local variable or function named 'Esempio' is already defined in this scope

Se cambiamo il tipo di parametro da una data posizione della lista dei parametri a un tipo diverso, in C# conteranno come due metodi assolutamente diversi, o più precisamente detto, diverse varianti di un metodo con lo stesso nome.

Ad esempio, se nel secondo metodo, il secondo parametro della lista dei parametri di uno dei metodi, float p2, è dichiarato non come float, ma come int per esempio, avremo due metodi diversi con due firme diverse: Esempio(int, float) e Esempio(int, int).

Ora il secondo elemento della loro firma, ossia la lista dei parametri, è diverso, a causa della differenza del tipo del loro secondo elemento:

static void Esempio(int p1, float p2) { }
static void Esempio(int param1, int param2) { }

In questo caso, anche se digitiamo lo stesso nome per i parametri, il compilatore accetterà questa dichiarazione, perché sono praticamente metodi diversi:

static void Esempio(int param1, float param2) { }
static void Esempio(int param1, int param2) { }

Il compilatore accetterà nuovamente il codice se dichiariamo due varianti del metodo, ma questa volta cambieremo l'ordine dei parametri invece del loro tipo.

static void Esempio(int param1, float param2) { }
static void Esempio(float param2, int param1) { }

Nell'esempio di sopra, l'ordine dei tipi di parametro è diverso e questo rende diversa anche la firma.

Poiché le liste dei parametri sono diverse, non ha importanza che il nome (Esempio) sia lo stesso per entrambi i metodi. Abbiamo comunque firme diverse per entrambi i metodi.

Definizione

Firma del Metodo

La Firma del Metodo è composta dal nome del metodo e dalla lista dei tipi dei parametri. Il nome dei parametri del metodo non è significativo per la dichiarazione del metodo così come il tipo di ritorno del metodo.

Invocazione di Metodi Sovraccaricati

Poiché abbiamo dichiarato metodi con lo stesso nome e firme diverse, possiamo invocare ciascuno di essi come qualsiasi altro metodo: semplicemente usando il loro nome e argomenti.

Ecco un esempio:

static void StampaNumeri(int valoreInt, float valoreFloat)
{
    Console.WriteLine("StampaNumeri: int, float");
    Console.WriteLine(valoreInt + "; " + valoreFloat);
}

static void StampaNumeri(float valoreFloat, int valoreInt)
{
    Console.WriteLine("StampaNumeri: float, int");
    Console.WriteLine(valoreFloat + "; " + valoreInt);
}

static void Main()
{
    StampaNumeri(2.71f, 2);
    StampaNumeri(5, 3.14159f);
}

Quando il codice viene eseguito, vedremo che la prima invocazione si riferisce al secondo metodo, e la seconda invocazione si riferisce al primo metodo.

Quale metodo verrà invocato dipende dal tipo dei parametri utilizzati.

Il risultato dopo l'esecuzione del codice sopra è:

StampaNumeri: float, int
2.71; 2
StampaNumeri: int, float
5; 3.14159

Le righe seguenti, tuttavia, non verranno compilate ed eseguite:

static void Main()
{
    StampaNumeri(2, 3);
}

Il motivo per cui questo non funziona è che il compilatore tenta di convertire entrambi i numeri interi in tipi adatti prima di passarli a uno qualsiasi dei metodi chiamati StampaNumeri.

In questo caso, tuttavia, queste conversioni non sono uguali. Ci sono due opzioni possibili:

  1. Convertire il primo parametro in float e chiamare il metodo StampaNumeri(float, int)
  2. Convertire il secondo parametro in float e chiamare il metodo StampaNumeri(int, float).

Il problema è che il compilatore non è in grado di capire quali dei due metodi invocare. Infatti restituisce un messaggio di errore:

error CS0121: The call is ambiguous between the following methods or properties: 'Program.StampaNumeri(int, float)' and 'Program.StampaNumeri(float, int)'

Questa ambiguità deve essere risolta manualmente, e un modo per farlo è mostrato nell'esempio seguente:

static void Main()
{
    StampaNumeri((float)2, (short)3);
}

Il codice sopra verrà compilato senza errori, perché dopo che gli argomenti sono stati trasformati, è chiaramente deciso a quale metodo ci riferiamo: StampaNumeri(float, int).

Nota

Ambiguità nella Chiamata di Metodi Sovraccaricati

Se due metodi hanno lo stesso nome ma firme diverse, il compilatore C# determina quale metodo chiamare in base al tipo di parametro passato.

Tuttavia, se in fase di invocazione vengono passati argomenti non del tipo corretto ma comunque convertibili, potrebbe verificarsi un'ambiguità nella chiamata del metodo.

Per eliminare l'ambiguità, è necessario convertire manualmente gli argomenti in tipi appropriati.

In Sintesi

In questa lezione abbiamo appreso che:

  • Il sovraccarico dei metodi è una tecnica che consente di creare più metodi con lo stesso nome ma con firme diverse.
  • La firma di un metodo è composta dal nome del metodo e dalla lista dei tipi dei parametri.
  • I nomi dei parametri del metodo non sono significativi per la dichiarazione del metodo.
  • Se due metodi hanno lo stesso nome ma firme diverse, il compilatore C# determina quale metodo chiamare in base al tipo di parametro passato.
  • Se due metodi hanno lo stesso nome e firme identiche, il compilatore C# restituirà un errore.
  • Se due metodi hanno lo stesso nome ma firme diverse, il compilatore C# accetterà la dichiarazione.