CLR internals, Mono.Cecil

Mono.Cecil: Nothing stops you (well, almost)

One of the advantages of Cecil (like Reflection.Emit or writing IL directly) is that it based on the ECMA CLI standard. So the only limitation is if it meets the standard or not. Unlike, C#.

For example, in C#, there is a set of rules of how you can call to variable, type, assembly etc. But these rules is not a CLI rule. So if you need to do something illegal in C# but is legal from the CLI point of view, Cecil is your friend.

(BTW, C# expression evaluator itself generating “illegal” code, for example, when it generate class for lambda closure) .

Here is an example of give an illegal C# name to a method.

void ChangeMethodName()
{
//Before changing the method name, this will print "Start"
var assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("Start", BindingFlags.Static | BindingFlags.Public).
Invoke(null, null));

// Changing the name to illegal name
var module = ModuleDefinition.ReadModule(@"C:\temp\ClassLibrary1.dll");
TypeDefinition class1 =
module.Types.First(type => type.Name == "Class1");
var method = class1.Methods.First(m => m.Name == "Start");
method.Name = "###Start_v1.4.3.0";
module.Write(@"C:\temp\ClassLibrary1_new.dll");

//After changing the method name, this will print "###Start_v1.4.3.0"
assem = Assembly.LoadFile(@"C:\temp\ClassLibrary1_new.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("###Start_v1.4.3.0",
BindingFlags.Static|BindingFlags.Public).
Invoke(null, null));
}

class Class1
{
static string Start()
{
return $"my name is {MethodBase.GetCurrentMethod().Name}";
}
}