【问题标题】:Do event handlers need to exactly match the event signature?事件处理程序是否需要与事件签名完全匹配?
【发布时间】:2011-01-27 17:07:15
【问题描述】:

我想做如下的事情:

Public Class Form1
    Public Event Evt1(ByVal c As c1)
    Public Event Evt2(ByVal c As c2)

    Private Sub OnEvt1OrEvt2(ByVal c As c1) Handles Me.Evt1, Me.Evt2
    End Sub 
End Class

Public Class c1
End Class

Public Class c2
    Inherits c1
End Class

但是,它似乎是无效的语法,因为 OnEvt1OrEvt2 的签名与 Evt2 的签名不匹配。

有什么办法可以做到吗?

编辑: 上面的代码似乎对除我以外的所有人都可以正常工作,但它在 VS2005 SP1 中无法为我编译。

错误信息类似于:

错误 BC31029:方法 'Private Sub OnEvt1OrEvt2(c As WindowsApplication1.c1)' 无法处理 事件'公共事件 Evt2(c As WindowsApplication1.c2)',因为 签名不匹配。

编辑 2:

我在 msdn 中找到了这个, VB相关:

http://msdn.microsoft.com/en-us/library/ms973905.aspx

表单加载中的代码分配 的 Name 属性的值 三个 Bucket 对象。它还调用 AddHandler 直接把所有的 溢出事件 处理溢出过程。尽你所能 看,单个事件处理程序可以处理 多个事件,只要所有的 事件具有兼容参数列表。

(...)

版权所有 © 2002 线人 通信集团和微软 公司

(强调我的)

不过,没有关于两个“兼容参数列表”到底是什么的消息。

编辑 3:

好的,我找到了: http://msdn.microsoft.com/en-us/library/ms364068%28v=vs.80%29.aspx#vb9overview_topic10

轻松的代表

使用创建委托时 Visual Basic 中的 AddressOf 或句柄 8.0,针对绑定到委托标识符的方法之一 必须完全匹配的签名 委托人的类型。

它是在VB9中添加的。

【问题讨论】:

  • 基本上“兼容的参数列表”意味着方法签名中的每个参数类型必须与委托声明中的相应参数类型相同,或者必须有 引用转换(维护表示身份的)从委托的参数类型到方法的参数类型。
  • @Jon Skeet:我就是这么想的;该定义的任何来源?
  • C# 语言规范提供了详细信息,我确信它们对于支持此功能的 VB 版本是等效的。我现在没有关于我的参考资料,但如果你愿意,我可以稍后查找。
  • @Jon Skeet:我认为没有必要。我相信你的话 :-) 我想我家里有一份 C# 规范的副本,我会看看它(虽然它很旧,是 1.0 之前的书)。无论如何,非常感谢!

标签: .net vb.net inheritance event-handling


【解决方案1】:

您的代码从命令行为我编译。

我不知道该功能何时出现在 VB 中,但在 C# 中,这是 C# 1 和 C# 2 之间的区别之一。可以从具有 compatible 签名的方法创建委托,而不是要求完全匹配

编辑:鉴于您的问题编辑,看起来这是 VB8 / VS2005 的问题。它适用于 VS2008 和 VS2010 编译器(分别为 VB9 和 VB10)。

【讨论】:

  • @Jaime:啊哈,您使用的是 VS 2005。我想知道它是否是 VB9 中的新功能...
【解决方案2】:

为了使其工作,您需要定义您的事件,以便将参数作为 Object 类型传递,然后在事件处理程序中执行转换操作。

或者您可以定义 C1 和 C2 通用的接口,并将其用作参数。然后,如果接口上定义的方法合适,您可以“按原样”使用引用,或者您会再次发现自己正在执行强制转换操作。

请注意,如果您使用通用方法定义了一个接口,并且如果这些通用方法是事件处理程序使用所需的全部,那么您不需要执行任何类型的“TypeOf”确定来处理事件。

综上所述,我知道如果可能的话,最好尽可能遵循 .NET 中建立的事件签名标准:

Public Event SomethingHappened(ByVal Sender as Object, byVal e As System.EventArgs)

在我看来,您可能会创建一个从 System.EventArgs 继承的类(或多个类),然后定义一个自定义属性来访问您的自定义参数。这样,您仍然可以在 Sender 参数中传递对客户端对象的引用,然后访问您的自定义参数:

Public Class MyCustomEventArgs
    Inherits System.EventArgs

    Private _MyCustomInterface As ICustomInterface

    Public Property Myproperty As ICustomInterface
        Get As ICustomInterface
            Return _MyCustomInterface
        End Get
        Let(ByVal value As ICustomInterface)
            _MyCustomInterface = value
        End Let
    End Property
End Class

Public Sub HandleMyEvent(ByVal Sender As Object, byVal e As MyCustomEventArgs) Handles MyEvent
    Dim MyCustom Interface As ICustomInterface
    MyCustominterface = e.TheCustominterface
    MyCustominterface.DoSomething
End Sub

【讨论】:

  • 这并不能真正解决我的问题(这确实不是问题,正如 SoMoS 和 yodaj007 指出的那样),但我认为它回答了问题,所以我会接受你的回答.
【解决方案3】:

我是 C# 用户,并且是一个糟糕的 VB.NET 阅读器。自动在线转换实用程序无法帮助我处理您的代码,所以我从头开始编写。在我看到的每个事件调用中,我想实现两个想法:

  1. 使用 EventHandler 而不是声明自定义委托。
  2. 让您的基类派生自 EventArgs:

    public static void Main() {
        BaseEvent += OnSomething;
        DerivedEvent += OnSomething;
    }
    
    public static void OnSomething(Object sender, MyBase args) {
        // Awesome!
    }
    
    public static event EventHandler<MyBase> BaseEvent;
    public static event EventHandler<MyDerived> DerivedEvent;
    
    public class MyBase : EventArgs {}
    public class MyDerived : MyBase {}
    

    }

在实际创建了一个 VB.NET 控制台应用程序来尝试这个之后,我发现只需在你的代码编译中删除你的“...”,所以你基本上已经有了一个工作代码 sn-p...有问题吗?

【讨论】:

  • vs2005 无法编译。说:“方法 'Private Sub OnEvt1OrEvt2(c As WindowsApplication1.c1)' 无法处理事件 'Public Event Evt2(c As WindowsApplication1.c2)' 因为签名不匹配”。
  • 顺便说一句,我已经尝试使用 AddHandler 添加事件处理程序(这是 vb 方式),也没有运气。不过还是谢谢。
猜你喜欢
  • 2013-10-22
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 2015-12-19
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多