One area that VB.NET tends to try and cover up is working with events; others have briefly touched on some of the differences, but here's a little more on them:
VB.NET provides a WithEvents keyword for fields that raise events. If the field is declared WithEvents then you can add a Handles field.Event to the end of a method whose signature is compatible with the event; that method will automatically be a delegate of the event without needing to manually AddHandler and RemoveHandler (+= and -=).
Private WithEvents SomeField
Public Sub SomeField_SomeEvent(sender as Object, e as EventArgs) Handles SomeField.SomeEvent
Console.Writeline("SomeEvent occured")
End Sub
Event declarations and raising events are simplified a bit. VB.NET doesn't require that you check if an event is null prior to notifying listeners:
Public event SomeEvent as EventHandler(of SomeEventArg)
Public Sub SomeMethod()
RaiseEvent SomeEvent(Me, new EventArgs)
End Sub
One "hidden" feature of events in VB.NET is accessing the underlying MulticastDelegate, to do something like GetInvocationList() Note: the event is named SomeEvent and the code to access the multicastdelegate calls an invisible field named SomeEventEvent:
Public event SomeEvent as EventHandler(of SomeEventArg)
Public Sub SomeMethod()
// Note that SomeEvent's MulticastDelegate is accessed by appending
// another "Event" to the end, this sample is redundant but accurate.
// If the event was named ListChanged then it would be ListChangedEvent
dim invocationList = SomeEventEvent.GetInvocationList()
End Sub