Altra argomento che non citerò nella sessione per motivi di tempo sono i "Custom Events"
Anche questa feature è gia presente in C# (quanti la conoscono?...) e permette di implementare degli eventi dei quali abbiamo il controllo totale sia per quanto riguarda lo storage che per quanto riguarda la gestione della fasi di Attach, Detach e Raise di un evento.
...mi ri-spiego...
Tutti i programmatori VB sanno che è possibile creare una classe con un evento in questo modo:

Public Class A
 Public Event Signaled (info as String)
 Public Sub DoSomething()
  RaiseEvent Signaled("ok")
 End Sub
End Class

Un pò meno sanno che la stessa classe può essere scritta in maniera "C#" like ovvero:

Public Class A
 Public Delegate Sub SignaledDelegate(ByVal info As String)
 Public Event Signaled As SignaledDelegate
 Public Sub DoSomething()
  RaiseEvent Signaled("ok")
 End Sub
End Class

Le due definzioni sono equivalenti.
Non entro nei dettagli di quello che avviene a livello IL quando scriviamo una cosa del genere ma a questo punto mi chiedo: Come avviene il collegamento tra il mio delegate SignaledDelegate e il gestore dell'evento? e se volessi attivare un thread quando qualcuno sottoscrive un determinato evento? (e senza chiedere nulla a colui che lo sottoscrive)

Risposta: Custom Events.

VB2005 mi permette di scrivere:

Public Class B
 Public Delegate Sub SignaledHandler(ByVal info As String)
 Public Custom Event Signaled As SignaledHandler

 AddHandler(ByVal value As SignaledHandler)
 ...
 End AddHandler

 RemoveHandler(ByVal value As SignaledHandler)
 ...
 End RemoveHandler

 RaiseEvent(ByVal info As String)
 ...
 End RaiseEvent
 End Event
End Class

Dichiarando un evento usando la keyword Custom, l'IDE di VB2005 aggiungerà lo scheletro sopra riportato automaticamente e, completanto opportunamente i vari metodi, potete gestire come meglio credete un particolare evento.
Rifancedomi all'esempio precedente ecco come implementare un Custom Event il quale attiva un thread solo quando qualcuno sottoscrive l'evento Signaled.

Public Class A
 
Public Delegate Sub SignaledHandler(ByVal message As String)
 
Private mSignaled As SignaledHandler
 
Private mCount As Int32

Public Custom Event Signaled As SignaledHandler

AddHandler(ByVal value As SignaledHandler)
 mSignaled = DirectCast([Delegate].Combine(mSignaled, value), SignaledHandler)
 mCount += 1
 If (mCount > 0) Then StartMonitoringThread()
End AddHandler

RemoveHandler(ByVal value As SignaledHandler)
mSignaled = DirectCast([Delegate].Remove(mSignaled, value), SignaledHandler)
mCount -= 1
If (mCount = 0) Then StopMonitoringThread()
End RemoveHandler

RaiseEvent(ByVal message As String)
If (mSignaled IsNot Nothing) Then mSignaled(message)
End RaiseEvent
End Event

Public Sub DoSomething()
RaiseEvent Signaled("ok")
End Sub
End Class

Notate che in AddHandler e RemoveHandler non faccio altro che aggiungere o rimuovere il delegate alla invocationList del nostro field (che, a differenza di quanto avviene abitualmente in VB.NET o C#, non viene creato automaticamente dal compilatore) mentre in RaiseEvent verifico, usando IsNot (anche questa una novità di VB 2005...) che qualcuno abbia effettivamente sottoscritto il mio evento prima di generare l'evento (altrimenti avrei una NullReferenceException)

Quando avrete la CTP o la Beta1, se volete, provate ad usare questo esempio così da capire come funzionano esattamente i vari Addhandler/RemoveHandler/RaiseEvent del vostro Custom Event.