使用GetField调用InvokeMember。在VB.NET中找不到字段

时间:2010-03-10 00:04:12

标签: vb.net reflection

这可能很简单,但我似乎无法弄明白。

我有一堆由表单设计器创建的表单项(在frmAquRun.Designer.vb中)

Public WithEvents btnAquRunEvent1 As VisibiltyButtonLib.VisibilityButton
Public WithEvents btnAquRunEvent2 As VisibiltyButtonLib.VisibilityButton

...等

我基本上希望能够为一个函数提供一个数字访问这些字段。所以我写了这个函数。 (在frmAquRun.vb中)

Const EVENT_BUTTON_PREFIX As String = "btnAquRunEvent"
Public Function getEventButton(ByVal id As Integer) As Windows.Forms.Button

    Dim returnButton As Windows.Forms.Button = Nothing
    Try
        returnButton = DirectCast(Me.GetType().InvokeMember(eventButtonName, Reflection.BindingFlags.GetField Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance, Nothing, Me, Nothing), Windows.Forms.Button)
    Catch ex As Exception
    End Try
    Return returnButton
End Function

但似乎总是产生字段未找到的异常。 异常中的消息是“找不到”字段'ATSIS_ControlProgram.frmAquRun.btnAquRunEvent1'。“

消息中的命名空间和表单名称是正确的。知道我做错了吗?

2 个答案:

答案 0 :(得分:3)

问题在于,对于WithEvents字段,VB实际上创建了一个属性,该属性执行必要的事件处理程序附加和分离。生成的属性具有该字段的名称。实际的支持字段将重命名为_ +原始名称。 1)

因此,为了让代码工作,只需在_前面添加按钮名称前缀,或者使用与属性getter相对应的BindingFlag(而不是GetField)。

或者,您可以使用表单的Controls集合轻松完成此操作:

returnButton = DirectCast(Me.Controls(eventButtonName), Windows.Forms.Button)

但请注意,只有当按钮位于顶层时才会起作用,即不嵌套在窗体上的容器控件中。


1)这是VB编译器的一个实现细节,但是它是可移植的(尤其是对Mono的vbnc编译器),因为对WithEvents字段的处理进行了非常详细的描述在VB语言规范中。

答案 1 :(得分:0)

问题是事件处理程序不是真正的字段。在编译时,它们实际上是实现add_btnAquRunEventX,remove_btnAquRunEventX和fire_btnAquRunEventX方法的属性。有一些方法可以使用反射来解决这个问题,但这可能不是解决问题的最佳方法。相反,您只需创建一个List<>并使用事件处理程序填充它,然后索引到该列表。

我在VB语法方面有点生疏,但看起来应该是这样的:

Dim events = New List<EventHandler>()
events.Add( btnAquRunEvent1 )
events.Add( btnAquRunEvent2 )

....

events( 0 )( null, EventArgs.Empty )

退后一步,评估你为什么要按索引调用。可能有一种更简单的方法可以抽象出不涉及所有这种间接的整个事物。