0

Having read a great many posts on using reflection to get a list of methods in a given class, I am still having trouble getting that list and need to ask for help. This is my current code:

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

I call this method like this:

GetClassMethods(GetType(HomeController))

The return has 43 methods, but I only want the methods I wrote in the class. The image below shows the beginning of what was returned. My declared methods are in this list, but down at location 31-37. There are actually 9 declared methods, but this list doesn’t show the Private methods.

enter image description here

When I look at theType, I see the property I want. It is DeclaredMethods which shows every declared method, public and private.

enter image description here

However, I’m not able to access this property with a statement such as this.

Dim methodList = theType.DeclaredMethods

The returned error is that DelaredMethods is not a member of Type. So, my questions are multiple:

1) Most important, what code do I need to retrieve every declared method in the class, and only the methods I declared?

2) Why am I not able to access the property that gives the list of DeclaredMethods()?

  • Take a look at the this: List (top-level) declared variables in a Windows Form and the use of BindingFlags. That procedure is used to extract declared fields. You can adapt it to extract whatever you need it to. – Jimi Apr 15 at 23:48
  • theType.DeclaredMethods seems to be a property not a method, so you have to omit the (). – thehennyy Apr 16 at 5:04
  • @thehennyy That was my mistake in the post, I accidentally added the () but I didn't really use them. The property simply doesn't show up in Intellisense, although that sometimes rarely happens. I corrected the post. – Alan Apr 16 at 13:23
3

Try this:

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

or for some fun with generics:

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

The IsSpecialName filter excludes methods with compiler-generated names, such as the special methods used by the compiler to implement properties. You can also play around more with the flags if you need to include, say, NonPublic members as well.


Finally, whenever you have a method ending with Return something.ToList() (or which could end with it, as my adaption shows here), it's almost always better to change the method to return an IEnumerable(Of T) instead, and let the calling code call ToList() if it really needs it. So my first example above is really better like this:

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

Hey, that could be a single-liner. Then for those situations where you really need a list, you can do this:

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

You'll start to find in many situations you don't need to use ToList() at all; the generic IEnumerable was good enough. Certainly this is true anywhere you just use the result with For Each loop. Now suddenly the memory use in your programs are significantly reduced.

  • Wow, what an awesome answer. That was exciting. You not only answered my question, you moved my understanding of coding forward a few steps. Thanks! I have a few follow-ups if you don't mind. I had to add BindingFlags.NonPublic to pickup one of my declared methods that was declared Private; but I'm still missing 1 function. In my research I picked up a method that ultimately didn't work but was defined as Private Shared Function GetSubClasses(Of T)() As List(Of Type). This does not show with the BindingFlags currently set. Why might that be? – Alan Apr 16 at 15:26
  • I also noticed the .where for IsSpecialName didn't seem to have an impact on the returned results in the current situation. What are the conditions when IsSpecialName might come into play? – Alan Apr 16 at 15:29
  • 1
    The keyword is Shared. C# developers (and hence the .Net library authors) use static instead of Shared, and you can get this method by adding BindingFlags.Static. – Joel Coehoorn Apr 16 at 15:30
  • 1
    As mentioned, IsSpecialName tells you whether it's a compiler-generated name, such as used for properties. You should need that filter to exclude all the get_ and set_ names for properties. If those get_ and set_ names are actually part of your class type, consider creating properties instead. – Joel Coehoorn Apr 16 at 15:31
  • I don't normally use Get/Set in my code. Final follow-up (I think). I struggled a little to retrieve the name from Result because the query return, when viewed in debug mode, looked more complicated than it actually was. But after iterating through the returned object the name was easily retrieved. However, in the process I tried a version where I explicitly declared the result variable as MethodInfo(). Then the .name. property was explicitly exposed. Is that a bad idea? – Alan Apr 16 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.