Examining the method body using Reflection in .NET C#
May 4, 2017 Leave a comment
In this short post we saw how to extract the members of a class: constructors, properties, methods etc. Even more exciting is the fact that you can peek into the body of a method. Well, not the plain text C# or VB code, but the Intermediate Language – MSIL version of it.
The MethodBody object represents, as the name suggests, the body of a method including the local variables and the MSIL instructions. MethodBody is available on classes that derive from the MethodBase class, which are methods and constructors – MethodInfo and ConstructorInfo.
Consider the following Customer class:
public class Customer { private string _name; public Customer(string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("Customer name!"); _name = name; } public string Name { get { return _name; } } public string Address { get; set; } public int SomeValue { get; set; } public int ImportantCalculation() { int variable = 2; string stringVar = string.Empty; if (variable == 2) { stringVar = "two"; } else { stringVar = "hello"; } ImportantVoidMethod(); return 1000; } public void ImportantVoidMethod() { bool ok = false; SomeEnumeration enumeration = SomeEnumeration.ValueOne; switch (enumeration) { case SomeEnumeration.ValueOne: ok = true; break; case SomeEnumeration.ValueTwo: ok = false; break; default: ok = false; break; } } public enum SomeEnumeration { ValueOne = 1 , ValueTwo = 2 } public class SomeNestedClass { private string _someString; } }
The following code shows you how you can extract the methods and inspect them:
Type customerType = typeof(Customer); Console.WriteLine("Customer methods: "); MethodInfo[] methods = customerType.GetMethods(); foreach (MethodInfo mi in methods) { Console.WriteLine(mi.Name); MethodBody methodBody = mi.GetMethodBody(); if (methodBody != null) { byte[] ilCode = methodBody.GetILAsByteArray(); int maxStackSize = methodBody.MaxStackSize; IList<LocalVariableInfo> localVariables = methodBody.LocalVariables; Console.WriteLine("Max stack size: {0}", maxStackSize); Console.WriteLine("Local variables if any:"); foreach (LocalVariableInfo lvi in localVariables) { Console.WriteLine("Type: {0}, index: {1}.", lvi.LocalType, lvi.LocalIndex); } Console.WriteLine("IL code:"); StringBuilder stringifiedIlCode = new StringBuilder(); foreach (byte b in ilCode) { stringifiedIlCode.Append(string.Format("{0:x2} ", b)); } Console.WriteLine(stringifiedIlCode); } }
The MethodInfo array will include the properties that are turned into methods, e.g. Name will become get_Name, and also the methods inherited from Object such as ToString(). Here’s the output for ImportantVoidMethod and ImportantCalculation:
The LocalVariableInfo doesn’t contain the name of the variable because the metadata about a type doesn’t keep the variable name, only its order.
View all posts on Reflection here.