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.
