L’operatore VBA “And” valuta il secondo argomento quando il primo è falso?

Function Foo(thiscell As Range) As Boolean Foo = thiscell.hasFormula And (InStr(1, UCase(Split(thiscell.formula, Chr(40))(0)), "bar") > 0) End Function 

Questa funzione esiste per verificare la presenza di una determinata sottostringa (barra, in questo caso) prima del (.

Il caso che sto avendo problemi è quando la cella passata nella funzione è vuota, la thisCell.hasFormula è falsa, ma l’istruzione dopo la e è ancora in fase di valutazione. Questo mi dà un errore fuori indice nell’intervallo in runtime.

VBA continua effettivamente a valutare il secondo argomento su And, anche quando il primo era falso?

Quello che stai cercando è chiamato ” valutazione di cortocircuito “.

VBA non ce l’ha.

Puoi vedere un approccio che è probabilmente adattabile alla tua situazione qui .

L’approccio scelto è consistito nella sostituzione di un Select Case per l’ If . C’è anche un esempio di utilizzo di Ifs annidati.

Come detto dal DOK : No, VBA non ha una valutazione di cortocircuito.

Tecnicamente è più efficiente utilizzare 2 istruzioni If-then invece di utilizzare l’operatore AND , ma a meno che non lo si faccia un sacco di volte, non si noterebbero i risparmi, quindi optare per ciò che è più leggibile. E se vuoi diventare davvero tecnico, VBA gestisce più istruzioni If-then più velocemente di Select Case .

VBA è eccentrico 🙂

La risposta è sì, VBA non valuta il corto circuito.

Non è solo una questione di stile; fa una grande differenza in una situazione come questa:

 If i < = UBound(Arr, 1) And j <= UBound(Arr, 2) And Arr(i, 1) <= UBound(Arr2, 1) Then Arr2(Arr(i, 1), j) = Arr(i, j) End If 

... che non è corretto. Più appropriatamente:

 If i < = UBound(Arr, 1) And j <= UBound(Arr, 2) Then If Arr(i, 1) <= UBound(Arr2, 1) Then Arr2(Arr(i, 1), j) = Arr(i, j) End If End If 

O se hai un'avversione ai if annidati:

 If i > UBound(Arr, 1) Or j > UBound(Arr, 2) Then ' Do Nothing ElseIf Arr(i, 1) > UBound(Arr2, 1) Then ' Do Nothing Else Arr2(Arr(i, 1), j) = Arr(i, j) End If 

VBA ha un comportamento simile a un cortocircuito. Normalmente Null propaga attraverso le espressioni, ad es. 3 + Null è Null e True And Null è Null . Però:

? False And Null
False

Sembra un comportamento da cortocircuito – cosa sta succedendo? Null non si propaga quando l’altro argomento di una congiunzione ( And ) è False o 0 – il risultato è solo False o 0 . Non importa se è l’argomento di sinistra o di destra. Lo stesso vale se l’altro argomento di una disgiunzione ( Or ) è True o un numero intero diverso da zero (un valore in virgola mobile sarà arrotondato a un numero intero che utilizza questa regola ).

Quindi gli effetti collaterali e gli errori non possono essere prevenuti in argomenti a And e Or , ma la propagazione Null può essere “cortocircuitata”. Questo comportamento sembra essere ereditato da SQL .

Penso che questa sia la migliore pratica:

 sub my conditions() If Condition1=constraint1 then if Condition2=constraint2 then if condition3=constraint3 then ... .... end if end if end if else end if .... end if end sub 

In questo modo passerai solo attraverso le condizioni se e solo se la condizione i è soddisfatta.

Considera il codice macchina che deve essere eseguito. Il più veloce dovrebbe essere sulla falsariga di un mix di codice come …

se sfsf allora vai a SkipAB

se fdf poi goto andato BAD

se dffdefedwf goto quindi MustHave

SkipAB: se dsda> 4 allora MustHave

GoneBad: funzione di uscita

MustHave: ThisIS = true

‘salva solo pochi istanti in cui il programma deve eseguirlo molte migliaia di volte … ad esempio file che cerca una grande unità o quando viene usato un semplice test booleano per saltare una funzione che richiede tempo come trovare tutti i fogli e i nomi in un foglio di lavoro chiuso [codice]

  If Not wFF.UsingFileExtMatch Then GoTo SkipExt If Not wFF.OKFileEXTMatch Then GoTo BADFile 

SkipExt: If Not wFF.UsingFileNameMatch Then GoTo SkipFileMatch If Not wFF.OKFileNameMatch Then GoTo BADFile SkipFileMatch: Se non wFF.UsingDaysAgo Then GoTo SkipDaysAgo Se non wFF.OKDaysAgo Then GoTo BADFile SkipDaysAgo:

[/codice]