Guida al Visual Basic .NET
Capitolo 27° - Gli Operatori
Gli operatori sono speciali metodi che permettono di eseguire, appunto, operazioni tra due valori mediante l'uso di un simbolo (ad esempio,
+ per la somma, - per la differenza, eccetera...). Quando facciamo i calcoli, comunemente usando i tipi base numerici del Framework, come
Int16 o Double, usiamo praticamente sempre degli operatori. Essi non sono nulla di "straordinario", nel senso che anche se non sembra, data
la loro particolare sintassi, sono pur sempre definiti all'interno delle varie classi come normali membri (statici). Gli operatori, come
i tipi base, del resto, non si sottraggono alla globale astrazione degli linguaggi orientati agli oggetti: tutto è sempre incasellato
al posto giusto in una qualche classe. Ma questo lo vedremo più avanti quando parlerò della Reflection. Sorvolando su questa breve parentesi idilliaca, torniamo all'aspetto più concreto di questo capitolo. Anche il programmatore ha la possibilità di definire nuovi operatori per i tipi che ha creato: ad esempio, può scrivere operatori che operino tra strutture e tra classi. In genere, si preferisce adottare gli operatori nel caso delle strutture poiché, essendo tipi value, si prestano meglio - come idea, più che altro - al fatto di subire operazioni tramite simboli. Venendo alla pratica, la sintassi generale di un operatore è la seguente: Shared Operator [Simbolo]([Parametri]) As [Tipo Restituito] '... Return [Risultato] End OperatorCome si vede, la sintassi è molto simile a quella usata per dichiarare una funzione, ad eccezione della keyword e dell'identificatore. Inoltre, per far sì che l'operatore sia non solo sintatticamente, ma anche semanticamente valido, devono essere soddisfatte queste condizioni:
Module Module1 Public Structure Fraction 'Numeratore e denominatore Private _Numerator, _Denumerator As Int32 Public Property Numerator() As Int32 Get Return _Numerator End Get Set(ByVal value As Int32) _Numerator = value End Set End Property Public Property Denumerator() As Int32 Get Return _Denumerator End Get Set(ByVal value As Int32) If value <> 0 Then _Denumerator = value Else 'Il denominatore non può mai essere 0 'Dovremmo lanciare un'eccezione, ma vedremo più 'avanti come si fa. Per ora lo impostiamo a uno _Denumerator = 1 End If End Set End Property 'Costruttore con due parametri, che inizializza numeratore 'e denominatore Sub New(ByVal N As Int32, ByVal D As Int32) Me.Numerator = N Me.Denumerator = D End Sub 'Restituisce la Fraction sottoforma di stringa Function Show() As String Return Me.Numerator & " / " & Me.Denumerator End Function 'Semplifica la Fraction Sub Semplify() Dim X As Int32 'Prende X come il valore meno alto in modulo 'e lo inserisce in X. X servirà per un 'calcolo spicciolo del massimo comune divisore X = Math.Min(Math.Abs(Me.Numerator), Math.Abs(Me.Denumerator)) 'Prima di iniziare, per evitare errori, controlla 'se numeratore e denominatore sono entrambi negativi: 'in questo caso li divide per -1 If (Me.Numerator < 0) And (Me.Denumerator < 0) Then Me.Numerator /= -1 Me.Denumerator /= -1 End If 'E con un ciclo scova il valore più alto di X 'per cui sono divisibili sia numeratore che denominatore '(massimo comune divisore) e li divide per quel numero. 'Continua a decrementare X finché non trova un 'valore per cui siano divisibili sia numeratore che 'denominatore: dato che era partito dall'alto, questo 'sarà indubbiamente il MCD Do Until ((Me.Numerator Mod X = 0) And (Me.Denumerator Mod X = 0)) X -= 1 Loop 'Divide numeratore e denominatore per l'MCD Me.Numerator /= X Me.Denumerator /= X End Sub 'Somma due frazioni e restituisce la somma Shared Operator +(ByVal F1 As Fraction, ByVal F2 As Fraction) _ As Fraction Dim F3 As Fraction 'Se i denumeratori sono uguali, si limita a sommare 'i numeratori If F1.Denumerator = F2.Denumerator Then F3.Denumerator = F1.Denumerator F3.Numerator = F1.Numerator + F2.Numerator Else 'Altrimenti esegue tutta l'operazione 'x a x*b + a*y '- + - = --------- 'y b y*b F3.Denumerator = F1.Denumerator * F2.Denumerator F3.Numerator = F1.Numerator * F2.Denumerator + F2.Numerator * F1.Denumerator End If 'Semplifica la Fraction F3.Semplify() Return F3 End Operator 'Sottrae due Fraction e restituisce la differenza Shared Operator -(ByVal F1 As Fraction, ByVal F2 As Fraction) _ As Fraction 'Somma l'opposto del secondo membro F2.Numerator = -F2.Numerator Return F1 + F2 End Operator 'Moltiplica due frazioni e restituisce il prodotto Shared Operator *(ByVal F1 As Fraction, ByVal F2 As Fraction) _ As Fraction 'Inizializza F3 con il numeratore pari al prodotto 'dei numeratori e il denominatore pari al prodotto dei 'denominatori Dim F3 As Fraction = New Fraction(F1.Numerator * F2.Numerator, _ F1.Denumerator * F2.Denumerator) F3.Semplify() Return F3 End Operator 'Divide due frazioni e restituisce il quoziente Shared Operator /(ByVal F1 As Fraction, ByVal F2 As Fraction) _ As Fraction 'Inizializza F3 eseguendo l'operazione: 'a x a y '- / - = - * - 'b y b x Dim F3 As Fraction = New Fraction(F1.Numerator * F2.Denumerator, _ F1.Denumerator * F2.Numerator) F3.Semplify() Return F3 End Operator End Structure Sub Main() Dim A As New Fraction(8, 112) Dim B As New Fraction(3, 15) A.Semplify() B.Semplify() Console.WriteLine(A.Show()) Console.WriteLine(B.Show()) Dim C As Fraction = A + B Console.WriteLine("A + B = " & C.Show()) Console.ReadKey() End Sub End Module CTypeCType è un particolare operatore che serve per convertire da un tipo di dato ad un altro. Non è ancora stato introdotto nei precedenti capitoli, ma ne parlerò più ampiamente in uno dei successivi. Scrivo comunque un paragrafo a questo riguardo per amor di completezza e utilità di consultazione.Come è noto, CType può eseguire conversioni da e verso tipi conosciuti: la sua sintassi, tuttavia, potrebbe sviare dalla corretta dichiarazione. Infatti, nonostante CType accetti due parametri, la sua dichiarazione ne implica uno solo, ossia il tipo che si desidera convertire, in questo caso Fraction. Il secondo parametro è implicitamente indicato dal tipo di ritorno: se scrivessimo "CType(ByVal F As Fraction) As Double", questa istruzione genererebbe un CType in grado di convertire dal tipo Fraction al tipo Double nella maniera consueta in cui siamo abituati: Dim F As Fraction '... Dim D As Double = CType(F, Double)La dichiarazione di una conversione verso Double genera automaticamente anche l'operatore CDbl, che si può usare tranquillamente al posto della versione completa di CType. Ora conviene porre l'accento sul come CType viene dichiarato: la sua sintassi non è speciale solo perchè può essere confuso da unario a binario, ma anche perchè deve dichiarare sempre se una conversione è Widening (di espansione, ossia senza perdita di dati) o Narrowing (di riduzione, con possibile perdita di dati). Per questo motivo si deve specificare una delle suddette keyword tra Shared e Operator. Ad esempio: Fraction rappresenta un numero razionale e, sebbene Double non rappresenti tutte le cifre di un possibile numero periodico, possiamo considerare che nel passaggio verso i Double non ci sia perdita di dati nè di precisione in modo rilevante. Possiamo quindi definire la conversione Widening: Shared Widening Operator CType(ByVal F As Fraction) As Double Return F.Numerator / F.Denumerator End OperatorInvece, la conversione verso un numero intero implica non solo una perdita di precisione rilevante ma anche di dati, quindi la definiremo Narrowing: Shared Narrowing Operator CType(ByVal F As Fraction) As Int32 'Notare l'operatore di divisione intera (per maggiori 'informazioni sulla divisione intera, vedere capitolo A6) Return F.Numerator F.Denumerator End Operator Operatori di confrontoGli operatori di confronto godono anch'essi di una caratteristica particolare: devono sempre essere definiti in coppia, < con >, = con <>, <= con >=. Non può infatti esistere un modo per verificare se una variabile è minore di un altra e non se è maggiore. Se manca uno degli operatori complementari, il compilatore visualizzerà un messaggio di errore. Ovviamente, il tipo restituito dagli operatori di confronto sarà sempre Boolean, poiché una condizione può essere solo o vera o falsa.Shared Operator <(ByVal F1 As Fraction, ByVal F2 As Fraction) As Boolean 'Converte le frazioni in double e confronta questi valori Return (CType(F1, Double) < CType(F2, Double)) End Operator Shared Operator >(ByVal F1 As Fraction, ByVal F2 As Fraction) As Boolean Return (CDbl(F1) > CDbl(F2)) End Operator Shared Operator =(ByVal F1 As Fraction, ByVal F2 As Fraction) As Boolean Return (CDbl(F1) = CDbl(F2)) End Operator Shared Operator <>(ByVal F1 As Fraction, ByVal F2 As Fraction) As Boolean 'L'operatore "diverso" restituisce sempre un valore opposto 'all'operatore "uguale" Return Not (F1 = F2) End OperatorÈ da notare che le espressioni come (a=b) o (a-c>b) restituiscano un valore booleano. Possono anche essere usate nelle espressioni, ma è sconsigliabile, in quanto il valore di True è spesse volte confuso: in VB.NET è -1, ma a runtime è 1, mentre negli altri linguaggi è sempre 1. Queste espressioni possono tuttavia essere assegnate con sicurezza ad altri valori booleani: '... a = 10 b = 20 Console.WriteLine("a è maggiore di b: " & (a > b)) 'A schermo compare: "a è maggiore di b: False"
C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...
|