|
L'Overloading è la capacità di un linguaggio ad oggetti di poter definire, nella stessa classe, più varianti dello stesso
metodo. Per poter eseguire correttamente l'overloading, è che ogni variante del metodo abbia queste caratteristiche:
- Sia della stessa categoria (procedura O funzione, anzi, per dirla in modo più esplicito: procedura Xor funzione);
- Abbia lo stesso nome;
- Abbia signature diversa da tutte le altre varianti. Per coloro che non se lo ricordassero, la signature di un metodo indica il tipo
e la quantità dei suoi parametri. Questo è il tratto essenziale che permette di differenziare concretamente una variante
dall'altra.
Per fare un esempio, il metodo Console.WriteLine espone ben 18 versioni diverse, che ci consentono di stampare pressoché ogni dato
sullo schermo. Fra quelle che non abbiamo mai usato, ce n'è una in particolare che vale la pena di introdurre ora, poiché
molto utile e flessibile. Essa prevede un primo parametro di tipo stringa e un secondo ParamArray di oggetti:
Console.WriteLine("stringa", arg0, arg1, arg2, arg3, ...)
Il primo parametro prende il nome di stringa di formato, poiché specifica il formato in cui i dati costituiti dagli argomenti
addizionali dovranno essere visualizzati. All'interno di questa stringa, si possono specificare, oltre ai normali caratteri, dei codici
speciali, nella forma "{I}", dove I è un numero compreso tra 0 e il numero di paramtri meno uno: "{I}" viene detto segnaposto e verrà
sostituito dal parametro I nella stringa. Ad esempio:
A = 1
B = 3
Console.WriteLine("La somma di {0} e {1} è {2}.", A, B, A + B)
'> "La somma di 1 e 3 è 4."
Ulteriori informazioni sulle stringhe di formato sono disponibili nel capitolo "Magie con le stringhe".
Ma ora passiamo alla dichiarazione dei metodi in overload. La parola chiave da usare, ovviamente, è Overloads, specificata poco dopo
lo scope, e dopo gli eventuali Overridable od Overrides. Le entità che possono essere sottoposte ad overload, oltre ai metodi,
sono:
- Metodi statici
- Operatori
- Proprietà
- Costruttori
- Distruttori
Anche se gli ultimi due sono sempre metodi - per ora tralasciamo i distruttori, che non abbiamo ancora analizzato - è bene specificare
con precisione, perchè a compiti speciali spesso corrispondono comportamenti altrettanto speciali. Ecco un semplicissimo esempio di
overload:
Module Module1
'Restituisce il numero di secondi passati dalla data D a oggi
Private Function GetElapsed(ByVal D As Date) As Single
Return (Date.Now - D).TotalSeconds
End Function
'Come sopra, ma il parametro è di tipo intero e indica
'un anno qualsiasi
Private Function GetElapsed(ByVal Year As Int32) As Single
'Utilizza Year per costruire un nuovo valore Date
'e usa la precedente variante del metodo per
'ottenere il risultato
Return GetElapsed(New Date(Year, 1, 1))
End Function
'Come le due sopra, ma il parametro è di tipo stringa
'e indica la data
Private Function GetElapsed(ByVal D As String) As Single
Return GetElapsed(Date.Parse(D))
End Function
Sub Main()
'GetElapsed viene chiamata con tre tipi di parametri
'diversi, ma sono tutti leciti
Dim El1 As Single = GetElapsed(New Date(1987, 12, 4))
Dim El2 As Single = GetElapsed(1879)
Dim El3 As Single = GetElapsed("12/12/1991")
Console.ReadKey()
End Sub
End Module
Come avrete notato, nell'esempio precedente non ho usato la keyword Overloads: anche se le regole dicono che i membri in overload vanno
segnati, non è sempre necessario farlo. Anzi, molte volte si evita di dichiarare esplicitamente i membri di cui esistono varianti
come Overloads. Ci sono varie ragioni per questa pratica: l'overload è scontato se i metodi presentano lo stesso nome, e il compilatore
riesce comunque a distinguere tutto nitidamente; inoltre, capita spesso di definire varianti e per rendere il codice più leggibile
e meno pesante (anche se i sorgenti in VB tendono ad essere un poco prolissi), si omette Overloads. Tuttavia, esistono casi in cui è
assolutamente necessario usare la keyword; eccone un esempio:
Module Module1
Class Person
Protected _FirstName, _LastName As String
Private ReadOnly _BirthDay As Date
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal Value As String)
If Value <> "" Then
_FirstName = Value
End If
End Set
End Property
Public Overridable Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal Value As String)
If Value <> "" Then
_LastName = Value
End If
End Set
End Property
Public ReadOnly Property BirthDay() As Date
Get
Return _BirthDay
End Get
End Property
Public Overridable ReadOnly Property CompleteName() As String
Get
Return _FirstName & " " & _LastName
End Get
End Property
'ToString è una funzione definita nella classe
'System.Object e poiché ogni cosa in .NET
'deriva da questa classe, &egrae; sempre possibile
'ridefinire tramite polimorfismo il metodo ToString.
'In questo caso ne scriveremo non una, ma due versioni,
'quindi deve essere dichiarato sia Overrides, perchè
'sovrascrive System.Object.ToString, sia Overloads,
'perchè è una versione alternativa di
'quella che andremo a scrivere tra poco
Public Overloads Overrides Function ToString() As String
Return CompleteName
End Function
'Questa versione accetta un parametro stringa che assume
'la funzione di stringa di formato: il metodo restituirà
'la frase immessa, sostituendo {F} con FirstName e {L} con
'LastName. In questa versione è sufficiente
'Overloads, dato che non esiste un metodo ToString che
'accetti un parametro stringa in System.Object e perciò
'non lo potremmo modificare
Public Overloads Function ToString(ByVal FormatString As String) _
As String
Dim Temp As String = FormatString
'Sostituisce {F} con FirstName
Temp = Temp.Replace("{F}", _FirstName)
'Sostituisce {L} con LastName
Temp = Temp.Replace("{L}", _LastName)
Return Temp
End Function
Sub New(ByVal FirstName As String, ByVal LastName As String, _
ByVal BirthDay As Date)
Me.FirstName = FirstName
Me.LastName = LastName
Me._BirthDay = BirthDay
End Sub
End Class
Sub Main()
Dim P As New Person("Mario", "Rossi", Date.Parse("17/07/67"))
Console.WriteLine(P.ToString)
'> Mario Rossi
'vbCrLf è una costante che rappresenta il carattere
'"a capo"
Console.WriteLine(P.ToString("Nome: {F}" & vbCrLf & "Cognome: {L}"))
'> Nome: Mario
'> Cognome: Rossi
Console.ReadKey()
End Sub
End Module
Come mostrato dall'esempio, quando il membro di cui si vogliono definire varianti è sottoposto anche a polimorfismo, è necessario
specificare la keyword Overloads, poiché, in caso contrario, il compilatore rintraccerebbe quello stesso membro come diverso
e, non potendo esistere membri con lo stesso nome, produrrebbe un errore. |
|