Prendere decisioni ...

Ultima modifica: 28-05-2016

Quando in VBA dobbiamo prendere delle decisioni possiamo ricorrere alle seguenti istruzioni:

  1. If ... Then ... [End If]
  2. If ... Then ... Else ... End If
  3. If ... Then ... ElseIf ... Else ... End If
  4. Select Case ... Case ... Case Else End Select
  5. IIf ( ... , ... , ... )

Dei casi che di seguito vado a presentare è da porre particolare attenzione al quarto caso in cui si parla del Select Case. Infatti il codice impiega molto meno tempo a leggere e quindi eseguire le istruzioni condizionali se si imposta il Select Case, nei confronti di istruzioni impostate con If Then Else ecc. ecc.

Questa rapidità è maggiormente evidenziata specialmente quando esistono parecchi If da controllare.

Oltre a questo la scelta di Select Case è dettata anche da una migliore leggibilità del codice.

 

Ma cominciamo subito con alcuni esempi pratici.

 

Primo esempio

If condizione Then istruzioni

oppure

If condizione Then
istruzioni
End If

Queste sono le sintassi più semplici e possono essere scritte su singola riga o a blocchi.

Con questa sintassi, se condizione è vera eseguiamo un solo tipo di istruzione ossia abbiamo un solo risultato: SI o NO.

Condizione può essere VERA o FALSA: se vera abbiamo una certa azione, altrimenti nulla.

Azione può essere rappresentata da una o più istruzioni e, a seconda dei casi, può essere scritta sulla stessa riga della If condizione (singola riga) o su righe differenti (blocco di istruzioni). A seconda della nostra scelta [End If] può essere omessa o meno.

Esempio:

If a > b Then c = 10: d = 20 ' singola riga: viene omessa End If

oppure

If a > b Then ' a blocco e la fine del blocco viene indicata da End If
c = 10: d = 20
'..............
End If

Nel primo caso viene omessa la scrittura di End If, mentre nel secondo è obbligatorio indicare la fine del blocco con End If.

Come esempio avrei potuto anche scrivere semplicemente una cosa più semplice tipo:

If a > b Then c = 10

ma sarebbe stato troppo banale per cui ho preferito scrivere due istruzioni per sottolineare una cosa importante e generalmente poco documentata: su una singola riga si possono scrivere quante istruzioni si vuole, ma occorre separare le singole istruzioni da ":" (due punti).

Con questa istruzione normalmente ci aspettiamo una sola reazione: SI / NO; VERO / FALSO:

se condizione è vera avremo c = 10: d = 20 altrimenti niente.

Spesso possiamo anche semplificare ulteriormente la sintassi scrivendo:

If a Then c = 10: d = 20

In questo caso tuttavia si presume che a noi interessi solo due stati dell'oggetto della nostra condizione:

la variabile a può contenere dei valori

la variabile a è vuota

 

Secondo esempio

If condizione Then
' primo blocco istruzioni
Else
' secondo blocco istruzioni
End If

In questo caso verrà eseguito uno dei due blocchi istruzioni e si dice al codice:

se la condizione posta è vera compi le istruzioni poste qui di seguito;

altrimenti compi queste altre istruzioni.

Questa struttura, contrariamente a quella appena vista, consente di definire più blocchi di istruzioni uno solo dei quali verrà eseguito.

If a = 1 Then
b = 5     ' primo blocco di istruzioni
Else
b = 10    ' secondo blocco istruzioni
End If

 

In questo caso verrà eseguito uno dei due blocchi istruzioni e si dice al codice:

se la condizione posta è vera compi le istruzioni poste qui di seguito;

altrimenti compi queste altre istruzioni.

Equivalente all'esempio appena citato potrebbe essere anche il seguente nel quale inizialmente si definisce comunque una variabile e solo se la condizione posta dopo è vera se ne cambierà il valore:

b = 10
If a = 1 Then
b = 5
End If

oppure:

b = 10
If a = 1 Then b = 5

 

Terzo esempio

If condizione 1 Then
' primo blocco istruzioni
ElseIf condizione 2 Then
' secondo blocco istruzioni
ElseIf condizione 3 Then
' terzo blocco istruzioni
' ................. seguono altre eventuali condizioni con relativi blocchi isruzioni

[Else]
' ultimo eventuale blocco istruzioni
End If

In questo caso viene verificata la prima condizione; se questa risulta falsa viene verificata la seconda condizione e così via fino a quando non viene individuata una condizione che risulti vera. A questo punto viene eseguito il blocco istruzioni corrispondente e si esce quindi dal blocco condizionale per eseguire il codice eventualmente presente dopo l'istruzione End If.

Se necessario, possiamo omettere il blocco di istruzioni Else che, se inserito, sarebbe come dire:

se le condizioni poste non non sono state soddisfatte in nessuno dei casi esaminati, in ogni altro caso ....

 

Quarto esempio

Select Case elemento in osservazione
Case prima verifica
' primo blocco istruzioni
Case seconda verifica
' secondo blocco istruzioni
' altre eventuali verifiche
' ed altri eventuali blocchi istruzioni

Case Else
' ultimo eventuale blocco istruzioni
End Select

Potrebbe essere, questa, una sintassi alquanto più elegante e senz'altro più potente di quella appena vista nel precedente punto 3.

Passiamo subito ad un esempio pratico e vediamo nel contempo tutte le varie sintassi con cui si possono esprimere le verifiche da compiere: a seconda del valore che ha la nostra variabile occorre compiere una determinata azione

Select Case Numero ' Numero è la variabile in esame
Case 1 To 5 ' se Numero è compreso tra 1 e 5
' primo blocco istruzioni
Case 6, 7, 8 , 11 ' se Numero ha uno dei seguenti valori: 6 - 7 - 8 - 11
' secondo blocco istruzioni
Case 9 To 10 ' se Numero è compreso tra 9 e 10.
' terzo blocco istruzioni
Case 12 ' se Numero è uguale a 12
' quarto blocco istruzioni
Case Else ' in tutti gli altri casi
' ultimo blocco istruzioni
End Select

Anche in questo caso, come nel precedente punto 3, facciamo uso del blocco Case Else se dobbiamo verificare molte condizioni legate ad una determinata variabile.

Per costruire un blocco If ... Then ... ElseIf ... Then ... Else ... End If la costruzione del blocco If sarebbe stata, in questo caso, più complessa:

If numero >= 1 And numero <= 5 Then
' primo blocco istruzioni
ElseIf numero = 6 Or numero = 7 Or numero = 8 Or numero = 11 Then
' secondo blocco istruzioni
ElseIf numero = 9 And numero = 10 Then
' terzo blocco istruzioni
Else
' ultimo blocco istruzioni
End If

 

Questo è un altro esempio dell'utilizzo di Select Case:

Risposta = MsgBox("Scegliere un pulsante", _
vbYesNoCancel, _
"Dimostrazione pulsante")
Select Case Risposta
Case Is = vbYes
MsgBox "Hai scelto il pulsante - Sì"
Case Is = vbNo
MsgBox "Hai scelto il pulsante - No"
Case Is = vbCancel
MsgBox "Hai scelto il pulsante - Annulla"
End Select

In questo caso con l'istruzione Case viene utilizzato l'operatore "Is" per valutare la variabile che fa riferimento ad un oggetto.

Select Case valuta il valore restituito dalla Funzione MsgBox e in base a tale valore (contenuto in Risposta) controlla il pulsante che abbiamo premuto ed esegue il blocco di istruzioni relative al pulsante premuto.

E' possibile nidificare in un blocco If ... End If altri blocchi come nel seguente esempio:

If temperatura > 100 Then
         MsgBox "Ebollizione dell'acqua"
Else
        If temperatura > 50 Then
               MsgBox "Temperatura da estate torrida"
        Else
               MsgBox "temperatura sopportabile"
        End If
End If

N.B.

In certe strutture complesse, ma anche in quelle meno complesse, è buona norma, per facilitarne la lettura, usare una indentatura appropriata

 

Quinto esempio

E, dulcis in fundo, vorrei presentare una funzione poco nota perché poco usata: infatti non sono riuscito a raccogliere molte informazioni su questa funzione: IIf.

Innanzitutto una precisazione: mentre in tutti i casi fin qui visti, parlando di If o di Select Case, sentiamo parlare di Istruzioni, parlando di IIf intendiamo parlare di Funzione (vedi la Guida in linea).

Come tutte le funzioni la sintassi esige degli argomenti che in questo caso sono 3, tutti e 3 obbligatori ed è semplicissima da usare:

IIf(condizione, SeVero, SeFalso).

Questo un esempio banale in cui vogliamo scegliere il numero maggiore tra due numeri:

For i = 1 To 50000
a = Cells(i, 1): b = Cells(i, 2)
c = IIf(a > b, a, b)
Next

Infatti in questo caso cerchiamo il valore massimo tra due elementi e lo poniamo nella variabile c

La sintassi corrispondente da usare con la tradizionale istruzione If sarebbe la seguente:

For i = 1 To 50000
a = Cells(i, 1): b = Cells(i, 2)
If a > b Then
c = a
Else
c = b
End If
Next

In quest'altro caso vogliamo dividere il numero maggiore per il numero minore:

a = Cells(1, 1): b = Cells(1, 2)
d = IIf(a > b, Int(a / b), Int(b / a))

 

Note

 

Nel caso della divisione dobbiamo essere sicuri che nessuno dei due numeri che stiamo confrontando non contenga uno 0 (zero) in quanto l'esecuzione della precedente istruzione causerebbe un errore di divisione per zero. L'apparente anomalia dipende dal fatto che IIf funziona solo se entrambi le espressioni (SeVero, SeFalso) sono eseguibili correttamente. Mi spiego meglio.

Nella istruzione: d = IIf(a > b, Int(a / b), Int(b / a)) a prescindere dalla condizione posta (a > b) e dalla espressione che alla fine verrà accettata vengono eseguiti, prima di essere accettati, sia l'espressione Int(a / b) sia l'espressione Int(b / a) per cui se in a o in b sono stati posti dei valori uguali a 0 (zero) l'esecuzione di tali espressioni genera un errore di divisione per zero.

Non si può, quindi, passare alla funzione IIf la seguente assegnazione:

a = 5: b = 0

in questo caso sarebbe più opportuno usare il classico If o aggiungere un controllo per verificare la presenza dello 0 (zero):

If a <> 0 And b <> 0 Then
d = IIf(a > b, Int(a / b), Int(b / a))
End If

 

 

Qualcuno più attento potrebbe suggerire: "perché invece di fare l'assegnazione: a = Cells(i, 1): b = Cells(i, 2) non usiamo direttamente i riferimenti a queste celle per compiere le nostre elaborazioni?"

In questo caso il tempo di elaborazione raddoppierebbe quasi. Infatti ho provato con il seguente:

For i = 1 To 50000
c = IIf(Cells(i, 1) > Cells(i, 2), Cells(i, 1), Cells(i, 2))
Next

risparmiando una riga di istruzioni. Il tempo impiegato per elaborare 50.000 righe col primo metodo è stato di 5 secondi; il tempo impiegato col secondo metodo è risultato 8 secondi.