在 Visual Basic .NET 中,如何列出和调用具有给定自定义属性的所有 class 函数?

In Visual Basic .NET, how can I list and call all class functions with a given custom attribute?

我有一个 Windows Forms / Visual Basic .NET 应用程序,它基本上充当编辑器。它应该为用户提供的功能之一是能够 运行 为他们当前的项目制定一套规则,并报告它发现的任何问题。这些规则都将由表单中的 BackgroundWorker 对象 运行 执行,因此可以报告执行进度。

我实现这个的策略是给表单一堆私有实例方法,这些方法接收用户的项目数据(包含在,比如说,一个 ProjectData 对象中),运行 无论检查在该步骤中需要,并且 return 一个对象包含有关测试的可显示信息以及它是通过还是失败。 (为了便于讨论,我们称其为 class CheckResult)。所以,为了清楚起见,所有这些方法都有一个签名:

Private Function SomeCheckToRun(data As ProjectData) As CheckResult

可以 像往常一样定义所有这些方法,然后手动将它们逐一列出,以便在 BackgroundWorker 的 DoWork 事件处理程序中调用,但是方法似乎对于潜在的大量检查来说会变得乏味。如果我可以只定义我想要的每个方法 运行 并将其装饰成这样就好了,这样循环就可以自动找到每个这样的方法定义并 运行 它。

我想我想做的是定义一个自定义属性 class 用于指示哪些实例方法是 运行 作为检查(可能称为 CheckToRunAttribute),然后以某种方式使用反射来获取当前在表单中实现的所有这些方法的列表,并按顺序执行每个方法,也许通过为每个方法设置一个委托给 运行。这些方法总共有多少个,到目前为止已经执行了多少个,BackgroundWorker可以用它来指示整体进度。

到目前为止,我的代码结构在我看来类似于以下内容:

Private Sub MyBackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles MyBackgroundWorker.DoWork
    ' TODO: Get a list of all the <CheckToRun()> methods here,
    '       run each one in a loop, and report progress after each one.
End Sub

' Further down...

<CheckToRun()>
Private Function SomeCheckToRun(data As ProjectData) As CheckResult
    ' Check code in here.
End Function

<CheckToRun()>
Private Function AnotherCheckToRun(data As ProjectData) As CheckResult
    ' Check code in here.
End Function

<CheckToRun()>
Private Function YetAnotherCheckToRun(data As ProjectData) As CheckResult
    ' Check code in here.
End Function

' And so on...

虽然这不是我有太多经验的事情。我知道 Type.GetMethods() function, how to write custom attributes, and the Func(T, TResult) delegate,但我不确定如何将它们组合在一起以获得我想要的东西。

tl;dr: 给定一个 class 有多个私有实例函数遵循相同的签名并且都标记有相同的自定义属性,我如何计算有多少有然后 运行 每个?

您可以使用反射列出所有具有自定义属性的方法。这是一个 Linq 解决方案:

Dim methods = Me.GetType.GetMethods(Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)_
                      .Where(Function(m) m.GetCustomAttributes(GetType(CheckToRun), False)_
                      .Length > 0).ToArray()

然后 运行 他们喜欢:

For Each method As Reflection.MethodInfo In methods
   method.Invoke(Me, New Object() {methodParams})
Next