When calling the GetMethods function which lists the methods for a given type, we should keep in mind that this function does not return methods in a particular order. More specifically, the methods are not necessarily in the same order it has been declared in the source code. This discrepancy is due to some caching performed by the .NET Framework for better performance as explained in a post by Haibo Luo. This article is aimed at outlining solutions to order the methods returned by GetMethods in the declaring order.

Returned Index vs. Ordered Index

Even when reflection operations are executed on a CLR type for the first time, i.e., when the cache is empty, the order returned by GetMethods may not be the same as the declaration order. In the following example, a class with 200 randomly generated methods has been compiled. Each method has the same signature:

public class Test {
  public decimal AJODCUJQ(int parameter) {
    throw new NotImplementedException();
  }

 // 199 other methods with the same signature follow
}

The following call to GetMethods returns 200 MethodInfo instances.

typeof(Test).GetMethods(BindingFlags.Instance | 
                                         BindingFlags.Static | 
                                         BindingFlags.Public | 
                                         BindingFlags.DeclaredOnly);

The returned order is however different than the declared order. The first declared function (index #0) is returned as the 116th method. Several cut-offs points are visible: methods #170 to #199 are the first returned, followed by methods #85 to #169, then by methods #0 to 84. Such behaviors may not be noticeable for types having a smaller numbers of methods.

Solutions

Code using GetMethods cannot depend on the order in which methods are returned, because that order varies. Several strategies could be implemented to order the methods in the declaring order, i.e., the xth method declared in the original source code will be the xth method being returned.

MetaData Token

The first solution could use the MetaDataToken property of MethodInfo. A metadata token is used to locate the record that contains the metadata for an entity such as a type, a method, or a field. The metadata engine uses the token to index into a specific metadata table in a given metadata scope. By experience, we can observe a direct correlation between the value of the metadata token and the declared index of the related method. I have not found, however, the confirmation of such a behavior in the documentation and I cannot therefore advice to use this trick for production systems.

Visual Studio Automation

If the developed application can run in the context of Visual Studio, using Visual Studio Automation offers a rich alternative to reflection. Using this framework is, however, outside the scope of this article.

ICorDebug

ICorDebug is a managed debugging public API. MDbg, which can be downloaded from the Microsoft site, simplifies the functionalities by wrapping ICorDebug in a much simplier object model. Mike Stall provides an example which loads a pdb file and outputs the symbols as a XML file. In this example, it is shown how the MDbg API can extract the line numbers where the method has been declared. By using the information provided by MDbg, the methods returned by GetMethods can be sorted in the declaring order.

Implementation

The implementation relies on a core of services defined as interfaces:

public interface IMethodProvider
{
    MethodInfo[] GetMethods(Type type);
}
public interface IMethodFilter
{
   bool IsMatch(MethodInfo methodInfo);
   void Initialize();
}
public interface ILineNumberProvider
{
   int GetStartLineNumber(MethodInfo method);
}

The service which returns an array of methods is called IMethodProvider. A simple implementation of this service is done by PublicReflectionMethodProvider which directly calls GetMethods. This implementation, as we have seen it previously, does not guaranty that the methods will be sorted in the same order as they have been declared. OrderedMethodProvider implements also IMethodProvider but returns ordered methods thanks to the help of an inner service ILineNumberProvider. ILineNumberProvider is implemented by MDbgLineNumberProvider which extracts the line number by using the MDbg library. If the pdb file related to the MethodInfo does not exist, a FileNotFoundException is thrown. Note that other implementations could use the metadata token or Visual Studio Automation.