事件处理程序是否需要与事件签名完全匹配?

时间:2011-01-27 17:07:15

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

我想做以下事情:

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找到了这个,   动相关的:

     

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

     

表单加载中的代码分配   值的Name属性   三个桶对象。它也叫   AddHandler指向所有的   溢出事件到   HandleOverflow程序。尽你所能   看,单个事件处理程序可以处理   多个事件,只要全部   事件有兼容参数列表。

     

(...)

     

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

(强调我的)

但是,没有关于两个“兼容的参数列表”的确切内容。

编辑3:

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

  

轻松的代表

     

使用时创建委托   在Visual Basic中AddressOf或Handles   8.0,目标是绑定到委托标识符的方法之一   必须与签名完全匹配   代表的类型。

它是在VB9中添加的。

3 个答案:

答案 0 :(得分:2)

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

我不知道该功能何时出现在VB中,但在C#中,这是C#1和C#2之间的差异之一。代理可以使用兼容签名的方法创建,而不是要求完全匹配。

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

答案 1 :(得分:1)

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

  1. 使用EventHandler< T>而不是声明自定义代理。
  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 {}
    

    }

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

答案 2 :(得分:1)

为了使其工作,您需要定义事件,使参数作为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