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:
The following call to
GetMethods returns 200
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.
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.
The first solution could use the
MetaDataToken property of
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.
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 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.
The implementation relies on a core of services defined as interfaces:
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 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.
The source code for this post is available from github.