EventHandler and Delegate misunderstanding

2019-04-13 17:43发布

问题:

Please take a look at the code below, which works as I would expect:

Partial Class _Default
    Inherits System.Web.UI.Page


    Delegate Sub TestEventHandler(ByVal o As Object, ByVal e As EventArgs)
    Dim alhandler As TestEventHandler = AddressOf TestEventMethod
    Public Event Test1 As TestEventHandler
    Public Event Test2 As TestEventHandler

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        AddHandler Me.Test1, alhandler
        AddHandler Me.Test2, alhandler
        RaiseEvent Test1(Me, e)
        RaiseEvent Test2(Me, e)
        RemoveHandler Me.Test1, alhandler
        RaiseEvent Test1(Me, e)
    End Sub

    Public Sub TestEventMethod(ByVal o As Object, ByVal e As EventArgs)
        MsgBox("Test")
    End Sub


End Class

I am confused with the two statements below:

Dim alhandler As TestEventHandler = AddressOf TestEventMethod '1
Public Event Test1 As TestEventHandler '2

1) This is saying that the reference of alHandler is a delegate that points to the address of a function. 2) This is saying that Test1 is an event of type Delegate. How can an event and a handler be a delegate?

回答1:

As others have said, each type of delegate is a type, just as if it were a regular class. So, in your example code, TestEventHandler is a delegate type. A TestEventHandler variable can reference any TestEventHandler object, just like any other variable can reference any object of its own type. TestEventHandler objects must be instantiated, just like objects of any other type.

Delegates are special, however, in that you declare them using a different, special, syntax. For instance, if you had the following method:

Public Sub MyMethod(Text As String)
    ' ...
End Sub

You could create a delegate that matches that method signature like this:

Public Delegate Sub MyMethodDelegate(Text As String)

Remember, by doing so, that simply defines the MyMethodDelegate type. That doesn't declare a variable of that type nor does it instantiate an object of that type.

There are two things in VB.NET syntax, however, which often cause a lot of confusion. First, when you declare an event, you can use two different syntax:

Public Event MyEvent As MyMethodDelegate
Public Event MyEvent(Text As String)

Both of those lines do the same thing. The first line defines the event using an already defined delegate type. The second line essentially defines a new unnamed delegate on the fly and then uses it as the type for the event. (Note, I'm using the MyMethodDelegate for simplicity, and that will work, but standards dictate that events should have a sender and an event args.) When an event is declared, think of it like a variable. Behind the scenes, it's really like a collection object that keeps a list of all the delegate objects that are added to it using the AddHandler function.

The second confusing thing in VB.NET is that the compiler will automatically instantiate a new delegate object for you, if necessary, when you use the AddressOf function. So, for instance, when you do something like this:

AddHandler myObject.MyEvent, AddressOf MyMethod

It's just a shortcut for typing the full text, like this:

AddHandler myObject.MyEvent, New MyMethodDelegate(AddressOf MyMethod)

The latter, in my opinion is much more clear. What you are actually doing is creating a new object of that delegate type and pointing that delegate object to that method, and then adding that delegate object to the event (that event collection-like variable defined by the object's type).

So, in your example, this line:

Dim alhandler As TestEventHandler = AddressOf TestEventMethod

Would be more clearly written as:

Dim alhandler As TestEventHandler = New TestEventHandler(AddressOf TestEventMethod)

It's declaring a delegate variable and then setting it to a new delegate object that points to that particular method. In this case, it's just a standard delegate variable, not an event. Events are very similar to delegates field/properties. Events are essentially an accessor wrapper around a private delegate field, in the same way that properties often wrap a private field. The big differences between delegate fields and events are that events support the AddHandler and EventHandler functions and events cannot be raised/invoked from outside of the class that defines it.