【问题标题】:Can't get a list of declared methods in a .net class无法获取 .net 类中声明的方法列表
【发布时间】:2019-04-15 23:36:28
【问题描述】:

阅读了大量关于使用反射获取给定类中的方法列表的帖子,但我仍然无法获得该列表,需要寻求帮助。这是我当前的代码:

Function GetClassMethods(ByVal theType As Type) As List(Of String)
    Dim methodNames As New List(Of String)
    For Each method In theType.GetMethods()
        methodNames.Add(method.Name)
    Next
    Return methodNames
End Function

我这样称呼这个方法:

GetClassMethods(GetType(HomeController))

return 有 43 个方法,但我只想要我在类中写的方法。下图显示了返回内容的开头。我声明的方法在此列表中,但位于位置 31-37。实际上有 9 个声明的方法,但是这个列表没有显示 Private 方法。

当我查看theType 时,我看到了我想要的属性。它是DeclaredMethods,它显示了每个声明的方法,公共的和私有的。

但是,我无法使用这样的语句访问此属性。

Dim methodList = theType.DeclaredMethods

返回的错误是DelaredMethods不是Type的成员。所以,我的问题是多方面的:

1) 最重要的是,我需要什么代码来检索类中每个声明的方法,并且只检索我声明的方法?

2) 为什么我无法访问提供 DeclaredMethods() 列表的属性?

【问题讨论】:

  • 看看this:List (top-level) declared variables in a Windows Form和BindingFlags的使用。该过程用于提取声明的字段。您可以对其进行调整以提取您需要的任何内容。
  • theType.DeclaredMethods 似乎是一个属性而不是一个方法,所以你必须省略 ()
  • @thehennyy 这是我在帖子中的错误,我不小心添加了(),但我并没有真正使用它们。该属性根本不会出现在 Intellisense 中,尽管这种情况有时很少发生。我更正了帖子。

标签: vb.net reflection


【解决方案1】:

试试这个:

Function GetClassMethods(ByVal theType As Type) As List(Of String)
    Dim flags = Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.DeclaredOnly
    Dim result = theType.GetMethods(flags).
          Where(Function(m)  Not m.IsSpecialName).
          Select(Function(m) m.Name)
    Return result.ToList()
End Function

或者为了一些泛型的乐趣:

Function GetClassMethods(Of T)() As List(Of String)
    Dim flags = Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.DeclaredOnly
    Dim result = GetType(T).GetMethods(flags).
          Where(Function(m)  Not m.IsSpecialName).
          Select(Function(m) m.Name)
    Return result.ToList()
End Function

IsSpecialName 过滤器排除具有编译器生成名称的方法,例如编译器用于实现属性的特殊方法。如果您还需要包括 NonPublic 成员,您还可以更多地使用标志。


最后,每当你有一个以Return something.ToList() 结尾的方法(或者可以以它结尾,正如我的改编在这里展示的那样),更改方法以返回IEnumerable(Of T) 几乎总是更好 strong>,如果确实需要,让调用代码调用ToList()。所以我上面的第一个例子真的更好:

Function GetClassMethods(ByVal theType As Type) As IEnumerable(Of String)
    Dim flags = Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.DeclaredOnly
    Return theType.GetMethods(flags).
          Where(Function(m)  Not m.IsSpecialName).
          Select(Function(m) m.Name)
End Function

嘿,那可能是单线。那么对于那些你确实需要列表的情况,你可以这样做:

Dim methodNames As List(Of String) = GetClassMethods(HomeController).ToList()

你会开始发现在很多情况下你根本不需要使用ToList();通用的IEnumerable 已经足够好了。当然,只要将结果与For Each 循环一起使用,任何地方都是如此。现在突然之间,您的程序中的内存使用量大大减少了。

【讨论】:

  • 哇,答案真棒。那是令人兴奋的。您不仅回答了我的问题,而且将我对编码的理解向前推进了几步。谢谢!如果你不介意的话,我有一些后续行动。我必须添加BindingFlags.NonPublic 来获取我声明的方法之一,该方法声明为Private;但我仍然缺少 1 个功能。在我的研究中,我选择了一种最终不起作用但被定义为Private Shared Function GetSubClasses(Of T)() As List(Of Type) 的方法。这不会在当前设置的 BindingFlags 中显示。为什么会这样?
  • 我还注意到IsSpecialName 的 .where 在当前情况下似乎对返回的结果没有影响。 IsSpecialName 可能发挥作用的条件是什么?
  • 关键字是Shared。 C# 开发人员(以及 .Net 库作者)使用 static 而不是 Shared,您可以通过添加 BindingFlags.Static 来获得此方法。
  • 如前所述,IsSpecialName 告诉您它是否是编译器生成的名称,例如用于属性。您应该需要该过滤器来排除属性的所有 get_set_ 名称。如果这些 get_set_ 名称实际上是您的类类型的一部分,请考虑改为创建属性。
  • 我通常不在我的代码中使用 Get/Set。最后的跟进(我认为)。从Result 中检索名称时我有点费力,因为在调试模式下查看查询返回时,看起来比实际更复杂。但是在遍历返回的对象之后,很容易检索到名称。但是,在此过程中,我尝试了一个版本,其中我将结果变量显式声明为MethodInfo()。然后.name. 属性被显式暴露。这是个坏主意吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多