【问题标题】:EventHandler and Delegate misunderstandingEventHandler与Delegate的误区
【发布时间】:2013-02-26 03:54:52
【问题描述】:

请看下面的代码,它按我的预期工作:

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

我对以下两种说法感到困惑:

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

1) 这是说 alHandler 的引用是一个委托 指向函数的地址。 2)这是说 Test1 是 委托类型的事件。事件和处理程序如何成为 委托?

【问题讨论】:

  • 事件处理程序只是代表的一个特定的type
  • @罗伯特哈维,谢谢。其他类型的代表是什么?
  • 那些不是事件处理程序的。 :) 您可以定义具有您想要的任何签名的委托类型。但是,既然你问了,这是框架中定义的另一个示例:Action<T>
  • Test1 变量是事件还是委托还是两者兼而有之?
  • 所有事件都是委托,但事件具有特定的签名和编译器支持。例如,您可以RaiseEvent

标签: vb.net delegates


【解决方案1】:

正如其他人所说,每种类型的委托都是一种类型,就像它是一个普通的类一样。因此,在您的示例代码中,TestEventHandler 是一个委托类型。 TestEventHandler 变量可以引用任何TestEventHandler 对象,就像任何其他变量可以引用其自身类型的任何对象一样。 TestEventHandler 对象必须被实例化,就像任何其他类型的对象一样。

但是,委托是特殊的,因为您使用不同的特殊语法声明它们。例如,如果您有以下方法:

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

您可以创建一个与该方法签名匹配的委托,如下所示:

Public Delegate Sub MyMethodDelegate(Text As String)

请记住,这样做只是定义了MyMethodDelegate 类型。这不会声明该类型的变量,也不会实例化该类型的对象。

然而,VB.NET 语法中有两件事经常引起很多混乱。首先,当你声明一个事件时,你可以使用两种不同的语法:

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

这两行都做同样的事情。第一行使用已定义的委托类型定义事件。第二行实质上是动态定义了一个新的未命名委托,然后将其用作事件的类型。 (注意,为了简单起见,我使用MyMethodDelegate,这会起作用,但标准规定事件应该有一个发送者和一个事件参数。) 当一个事件被声明时,想想它像一个变量。在幕后,它实际上就像一个集合对象,其中包含使用AddHandler 函数添加到其中的所有委托对象的列表。

VB.NET 中的第二个令人困惑的事情是,如果需要,当您使用AddressOf 函数时,编译器会自动为您实例化一个新的委托对象。因此,例如,当您执行以下操作时:

AddHandler myObject.MyEvent, AddressOf MyMethod

这只是输入全文的快捷方式,如下所示:

AddHandler myObject.MyEvent, New MyMethodDelegate(AddressOf MyMethod)

在我看来,后者要清楚得多。您实际上在做的是创建该委托类型的新对象并将该委托对象指向该方法,然后将该委托对象添加到事件(由对象类型定义的类似事件集合的变量)。

所以,在你的例子中,这一行:

Dim alhandler As TestEventHandler = AddressOf TestEventMethod

更清楚的写成:

Dim alhandler As TestEventHandler = New TestEventHandler(AddressOf TestEventMethod)

它声明了一个委托变量,然后将其设置为一个指向该特定方法的新委托对象。在这种情况下,它只是一个标准的委托变量,而不是一个事件。事件与委托字段/属性非常相似。事件本质上是私有委托字段周围的访问器包装器,就像属性通常包装私有字段一样。委托字段和事件之间的最大区别在于,事件支持 AddHandlerEventHandler 函数,并且不能从定义它的类外部引发/调用事件。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-12-27
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2022-01-12
相关资源
最近更新 更多