Delegati (Visual Basic)

I delegati sono oggetti che fanno riferimento ai metodi. Vengono a volte descritti come puntatori a funzione indipendenti dai tipi poiché sono simili ai puntatori a funzione usati in altri linguaggi di programmazione. A differenza dei puntatori a funzione, tuttavia, Visual Basic delegati sono un tipo riferimento basato sulla classe System.Delegate. I delegati possono fare riferimento sia a metodi condivisi, ovvero metodi che è possibile chiamare senza una specifica istanza di una classe, sia a metodi di istanza.

Delegati ed eventi

I delegati sono utili nelle situazioni in cui è necessario un intermediario tra una routine chiamante e la routine chiamata. Ad esempio, può essere necessario che un oggetto generatore di eventi sia in grado di chiamare gestori di eventi differenti in circostanze diverse. Purtroppo, l'oggetto che genera gli eventi non può sapere in anticipo quale gestore eventi gestirà uno specifico evento. Visual Basic consente di associare dinamicamente i gestori eventi agli eventi creando automaticamente un delegato quando si usa l'istruzione AddHandler . In fase di esecuzione, il delegato inoltrerà le chiamate al gestore eventi appropriato.

Anche se è possibile creare delegati personalizzati, nella maggior parte dei casi Visual Basic crea il delegato e gestisce automaticamente i dettagli. Un'istruzione Event, ad esempio, consente di definire implicitamente una classe delegata denominata <EventName>EventHandler come classe nidificata della classe contenente l'istruzione Event e con la stessa firma dell'evento. L'istruzione AddressOf crea in modo implicito un'istanza di un delegato che fa riferimento a una routine specifica. Le due righe di codice seguenti sono equivalenti. Nella prima riga è possibile osservare la creazione esplicita di un'istanza di EventHandler, con un riferimento al metodo Button1_Click inviato come argomento. La seconda riga rappresenta un modo più pratico di eseguire la stessa operazione.

AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)
' The following line of code is shorthand for the previous line.
AddHandler Button1.Click, AddressOf Me.Button1_Click

È possibile usare la sintassi abbreviata per creare delegati ogni volta che il compilatore è in grado di determinare il tipo del delegato in base al contesto.

Dichiarazione di eventi che usano un tipo delegato esistente

In alcune situazioni, è consigliabile dichiarare un evento che usa un tipo delegato esistente come delegato sottostante. La sintassi seguente illustra come eseguire tale operazione:

Delegate Sub DelegateType()
Event AnEvent As DelegateType

Questa operazione si rivela utile quando si vogliono inviare più eventi allo stesso gestore.

Variabili e parametri dei delegati

È possibile usare i delegati per altre attività non relative a eventi, ad esempio il modello di threading Free, oppure con routine che richiedono la chiamata di diverse versioni delle funzioni in fase di compilazione.

Si supponga, ad esempio, di avere un'applicazione di annunci pubblicitari che include una casella di riepilogo contenente nomi di automobili. Gli annunci sono ordinati per titolo, in genere corrispondente al modello dell'auto. Se per alcune auto il modello è preceduto dall'anno di produzione, può verificarsi un problema. Il problema consiste nel fatto che la funzionalità di ordinamento integrata della casella di riepilogo esegue l'ordinamento solo in base ai codici dei caratteri, elencando prima tutti gli annunci che iniziano con una data e quindi tutti quelli che iniziano con il modello.

Per risolvere il problema, è possibile creare una routine di ordinamento in una classe che usa l'ordinamento alfabetico standard per la maggior parte delle caselle di riepilogo, ma che è in grado di passare, in fase di esecuzione, alla routine di ordinamento personalizzata per gli annunci relativi alle automobili. A questo scopo, è necessario passare la routine di ordinamento personalizzata alla classe di ordinamento in fase di esecuzione usando i delegati.

Espressioni AddressOf e Lambda

Ogni classe delegata definisce un costruttore a cui viene passata la specifica di un metodo dell'oggetto. Un argomento di un costruttore di delegati deve essere un riferimento a un metodo o a un'espressione lambda.

Per specificare un riferimento a un metodo, usare la sintassi seguente:

AddressOf [expression.]methodName

Il tipo in fase di compilazione dell'elemento expression deve essere il nome di una classe o un'interfaccia contenente un metodo con il nome specificato la cui firma corrisponde a quella della classe delegata. Il metodo methodName può essere o un metodo condiviso o un metodo di istanza. methodName non è un elemento facoltativo, anche se si crea un delegato per il metodo predefinito della classe.

Per specificare un'espressione lambda, usare la sintassi seguente:

Function ([parm As type, parm2 As type2, ...]) expression

Nell'esempio seguente sono illustrate sia l'espressione AddressOf che l'espressione lambda usate per specificare il riferimento per un delegato.

Module Module1

    Sub Main()
        ' Create an instance of InOrderClass and assign values to the properties.
        ' InOrderClass method ShowInOrder displays the numbers in ascending 
        ' or descending order, depending on the comparison method you specify.
        Dim inOrder As New InOrderClass
        inOrder.Num1 = 5
        inOrder.Num2 = 4

        ' Use AddressOf to send a reference to the comparison function you want
        ' to use.
        inOrder.ShowInOrder(AddressOf GreaterThan)
        inOrder.ShowInOrder(AddressOf LessThan)

        ' Use lambda expressions to do the same thing.
        inOrder.ShowInOrder(Function(m, n) m > n)
        inOrder.ShowInOrder(Function(m, n) m < n)
    End Sub

    Function GreaterThan(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
        Return num1 > num2
    End Function

    Function LessThan(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
        Return num1 < num2
    End Function

    Class InOrderClass
        ' Define the delegate function for the comparisons.
        Delegate Function CompareNumbers(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
        ' Display properties in ascending or descending order.
        Sub ShowInOrder(ByVal compare As CompareNumbers)
            If compare(_num1, _num2) Then
                Console.WriteLine(_num1 & "  " & _num2)
            Else
                Console.WriteLine(_num2 & "  " & _num1)
            End If
        End Sub

        Private _num1 As Integer
        Property Num1() As Integer
            Get
                Return _num1
            End Get
            Set(ByVal value As Integer)
                _num1 = value
            End Set
        End Property

        Private _num2 As Integer
        Property Num2() As Integer
            Get
                Return _num2
            End Get
            Set(ByVal value As Integer)
                _num2 = value
            End Set
        End Property
    End Class
End Module

La firma della funzione deve corrispondere a quella del tipo delegato. Per altre informazioni sulle espressioni lambda, vedere Espressioni lambda. Per altri esempi di espressioni lambda e assegnazioni di AddressOf a delegati, vedere Conversione di tipo relaxed del delegato.

Titolo Descrizione
Procedura: richiamare un metodo delegato Viene offerto un esempio che mostra come associare un metodo a un delegato e quindi richiamare tale metodo tramite il delegato.
Procedura: passare una routine a un'altra routine in Visual Basic Viene illustrato come usare i delegati per passare una routine a un'altra routine.
Conversione di tipo relaxed del delegato Viene descritto come assegnare subroutine e funzioni a delegati o gestori anche quando le relative firme non sono identiche.
Eventi Viene offerta una panoramica degli eventi in Visual Basic.