Storia della questione:
Le procedure annidate (local functions) in Visual Basic sono apparse solo nelle versioni di VB.NET a partire da VB 15.0 (Visual Studio 2017), il che le distingue dal classico VB6, dove questa possibilità non esisteva. Questa caratteristica consente di dichiarare procedure all'interno di altre procedure, ampliando l'espressività del linguaggio e semplificando l'organizzazione della logica ausiliaria in un'unica area di visibilità.
Problema
Situazioni frequenti in cui una certa logica ausiliaria è necessaria solo all'interno di un metodo specifico e non è richiesta altrove. In passato, era necessario creare metodi privati di classe, aumentando il disordine nello spazio dei nomi e complicando la navigazione nel codice. Ma anche con le local functions ci si possono imbattere in problemi di visibilità, errori di accesso alle variabili e difficoltà di debug.
Soluzione
Le procedure annidate consentono di incapsulare la logica di servizio nella procedura "genitore", rendendo il codice più leggibile e limitando l'area di visibilità dei metodi ausiliari. In VB.NET, la dichiarazione di funzioni annidate appare così:
Sub MainProc() Dim x As Integer = 5 Dim y As Integer = 10 Console.WriteLine($"Somma — {Add(x, y)}") Function Add(a As Integer, b As Integer) As Integer Return a + b End Function End Sub
Caratteristiche chiave:
Le procedure annidate possono avere modificatori di accesso Public, Friend o Protected?
No, per le procedure annidate è consentito solo il livello di accessibilità all'interno della loro procedura "genitore". Non possono essere dichiarate come Public/Friend/Protected e sono accessibili solo localmente.
È possibile dichiarare una procedura annidata all'interno di una costruzione For o If?
No, le funzioni locali possono essere dichiarate solo al primo livello all'interno di un metodo (procedura), ma non all'interno di blocchi annidati (ad esempio, For, If, While).
Le procedure annidate possono essere asincrone (Async Sub/Function)?
Sì, è possibile dichiarare funzioni locali asincrone, permettendo di incapsulare la logica di esecuzione asincrona all'interno del metodo:
Async Sub DoOperationsAsync() Await LocalAsync() Async Function LocalAsync() As Task Await Task.Delay(1000) Console.WriteLine("Operazione asincrona completata.") End Function End Sub
Nel progetto sono stati eccessivamente utilizzati metodi privati invece di funzioni locali, il che ha portato a una decina di procedure di servizio a "disordinare" l'interfaccia della classe. La navigazione è diventata molto complessa.
Pro:
Contro:
Per la logica interna è stato utilizzato l'approccio con funzioni locali: tutta l'elaborazione di servizio è stata collocata all'interno del metodo principale, il codice è auto-documentato e facile da mantenere.
Pro:
Contro: