Procedure di risoluzione dei problemi (Visual Basic)
Questa pagina elenca alcuni problemi comuni che possono verificarsi durante l'utilizzo delle procedure.
Restituzione di un tipo di matrice da una routine di funzione
Se una Function
routine restituisce un tipo di dati matrice, non è possibile utilizzare il Function
nome per archiviare i valori negli elementi della matrice. Se si tenta di eseguire questa operazione, il compilatore lo interpreta come una chiamata a Function
. L'esempio seguente genera errori del compilatore:
Function AllOnes(n As Integer) As Integer()
For i As Integer = 1 To n - 1
' The following statement generates a COMPILER ERROR.
AllOnes(i) = 1
Next
' The following statement generates a COMPILER ERROR.
Return AllOnes()
End Function
L'istruzione AllOnes(i) = 1
genera un errore del compilatore perché sembra chiamare AllOnes
con un argomento del tipo di dati errato (scalare Integer
anziché una Integer
matrice). L'istruzione Return AllOnes()
genera un errore del compilatore perché sembra chiamare AllOnes
senza argomenti.
Approccio corretto: Per poter modificare gli elementi di una matrice da restituire, definire una matrice interna come variabile locale. L'esempio seguente viene compilato senza errori:
Function AllOnes(n As Integer) As Integer()
Dim iArray(n - 1) As Integer
For i = 0 To n - 1
iArray(i) = 1
Next
Return iArray
End Function
Argomento non modificato dalla chiamata di routine
Se si intende consentire a una routine di modificare un elemento di programmazione sottostante un argomento nel codice chiamante, è necessario passarlo per riferimento. Tuttavia, una routine può accedere agli elementi di un argomento di tipo riferimento anche se viene passata per valore.
Variabile sottostante. Per consentire alla routine di sostituire il valore dell'elemento variabile sottostante stesso, la routine deve dichiarare il parametro ByRef. Inoltre, il codice chiamante non deve racchiudere l'argomento tra parentesi, perché eseguirà l'override del
ByRef
meccanismo di passaggio.Elementi del tipo di riferimento. Se si dichiara un parametro ByVal, la routine non può modificare l'elemento variabile sottostante stesso. Tuttavia, se l'argomento è un tipo riferimento, la routine può modificare i membri dell'oggetto a cui punta, anche se non può sostituire il valore della variabile. Ad esempio, se l'argomento è una variabile di matrice, la routine non può assegnarvi una nuova matrice, ma può modificare uno o più dei relativi elementi. Gli elementi modificati si riflettono nella variabile di matrice sottostante nel codice chiamante.
Nell'esempio seguente vengono definite due procedure che accettano una variabile di matrice per valore e operano sui relativi elementi. La routine increase
aggiunge semplicemente uno a ogni elemento. La routine replace
assegna una nuova matrice al parametro a()
e quindi ne aggiunge una a ogni elemento. Tuttavia, la riassegnazione non influisce sulla variabile di matrice sottostante nel codice chiamante perché a()
è dichiarata ByVal
.
Public Sub increase(ByVal a() As Long)
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
Public Sub replace(ByVal a() As Long)
Dim k() As Long = {100, 200, 300}
a = k
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
L'esempio seguente effettua chiamate a increase
e replace
:
Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
La prima MsgBox
chiamata visualizza "After increase(n): 11, 21, 31, 41". Poiché n
è un tipo riferimento, increase
può modificare i relativi membri, anche se viene passato ByVal
.
La seconda MsgBox
chiamata visualizza "After replace(n): 11, 21, 31, 41". Poiché n
viene passato ByVal
, replace
non può modificare la variabile n
assegnando una nuova matrice. Quando replace
crea la nuova istanza k
della matrice e la assegna alla variabile a
locale , perde il riferimento a n
passato dal codice chiamante. Quando incrementa i membri di a
, viene interessata solo la matrice k
locale.
Approccio corretto: Per poter modificare un elemento variabile sottostante stesso, passarlo per riferimento. Nell'esempio seguente viene illustrata la modifica nella dichiarazione di replace
che consente di sostituire una matrice con un'altra nel codice chiamante:
Public Sub replace(ByRef a() As Long)
Impossibile definire un overload
Se si desidera definire una versione di overload di una routine, è necessario usare lo stesso nome ma una firma diversa. Se il compilatore non riesce a distinguere la dichiarazione da un overload con la stessa firma, viene generato un errore.
La firma di una routine è determinata dal nome della procedura e dall'elenco di parametri. Ogni overload deve avere lo stesso nome di tutti gli altri overload, ma deve essere diverso da tutti in almeno uno degli altri componenti della firma. Per altre informazioni, vedere Procedure Overloading.
Gli elementi seguenti, anche se sono relativi all'elenco di parametri, non sono componenti della firma di una procedura:
- Parole chiave del modificatore di routine, ad esempio
Public
,Shared
eStatic
. - Nomi dei parametri.
- Parole chiave del modificatore di parametri, ad esempio
ByRef
eOptional
. - Tipo di dati del valore restituito ,ad eccezione di un operatore di conversione.
Non è possibile eseguire l'overload di una routine variando solo uno o più degli elementi precedenti.
Approccio corretto: Per poter definire un overload di routine, è necessario variare la firma. Poiché è necessario usare lo stesso nome, è necessario variare il numero, l'ordine o i tipi di dati dei parametri. In una procedura generica è possibile variare il numero di parametri di tipo. In un operatore di conversione (funzione CType) è possibile variare il tipo restituito.
Risoluzione dell'overload con argomenti Facoltativi e ParamArray
Se si esegue l'overload di una routine con uno o più parametri Facoltativi o un parametro ParamArray , è necessario evitare di duplicare uno qualsiasi degli overload impliciti. Per informazioni, vedere Considerazioni in Procedure di overload.
Chiamata della versione errata di una procedura di overload
Se una routine include diverse versioni di overload, è necessario avere familiarità con tutti gli elenchi di parametri e comprendere in che modo Visual Basic risolve le chiamate tra gli overload. In caso contrario, è possibile chiamare un overload diverso da quello previsto.
Dopo aver determinato l'overload da chiamare, prestare attenzione a osservare le regole seguenti:
- Specificare il numero corretto di argomenti e nell'ordine corretto.
- Idealmente, gli argomenti devono avere gli stessi tipi di dati dei parametri corrispondenti. In ogni caso, il tipo di dati di ogni argomento deve essere esteso a quello del parametro corrispondente. Ciò vale anche con l'istruzione Option Strict impostata su
Off
. Se un overload richiede una conversione di tipo narrowing dall'elenco di argomenti, tale overload non è idoneo per essere chiamato. - Se si specificano argomenti che richiedono l'estensione, rendere i tipi di dati il più vicini possibile ai tipi di dati dei parametri corrispondenti. Se due o più overload accettano i tipi di dati dell'argomento, il compilatore risolve la chiamata all'overload che chiama la quantità minima di estensione.
È possibile ridurre la probabilità di mancata corrispondenza del tipo di dati usando la parola chiave di conversione della funzione CType durante la preparazione degli argomenti.
Errore di risoluzione dell'overload
Quando si chiama una routine di overload, il compilatore tenta di eliminare tutti gli overload, ma uno degli overload. Se ha esito positivo, risolve la chiamata a tale overload. Se elimina tutti gli overload o se non riesce a ridurre gli overload idonei a un singolo candidato, viene generato un errore.
L'esempio seguente illustra il processo di risoluzione dell'overload:
Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)
Nella prima chiamata, il compilatore elimina il primo overload perché il tipo del primo argomento (Short
) si restringe al tipo del parametro corrispondente (Byte
). Elimina quindi il terzo overload perché ogni tipo di argomento nel secondo overload (Short
e Single
) si estende al tipo corrispondente nel terzo overload (Integer
e Single
). Il secondo overload richiede meno estensione, quindi il compilatore lo usa per la chiamata.
Nella seconda chiamata, il compilatore non può eliminare alcun overload sulla base di un tipo di dati più piccolo. Elimina il terzo overload per lo stesso motivo della prima chiamata, perché può chiamare il secondo overload con minore estensione dei tipi di argomento. Tuttavia, il compilatore non è in grado di risolvere tra il primo e il secondo overload. Ognuno ha un tipo di parametro definito che si estende al tipo corrispondente nell'altro (Byte
a Short
, ma Single
a Double
). Il compilatore genera quindi un errore di risoluzione dell'overload.
Approccio corretto: Per poter chiamare una routine di overload senza ambiguità, usare la funzione CType per associare i tipi di dati dell'argomento ai tipi di parametro. Nell'esempio seguente viene illustrata una chiamata a z
che forza la risoluzione al secondo overload.
Call z(CType(p, Short), CType(q, Single))
Risoluzione dell'overload con argomenti Facoltativi e ParamArray
Se due overload di una routine hanno firme identiche, ad eccezione del fatto che l'ultimo parametro è dichiarato Facoltativo in uno e ParamArray nell'altro, il compilatore risolve una chiamata a tale routine in base alla corrispondenza più vicina. Per altre informazioni, vedere Overload Resolution.