Importing

jbevain edited this page May 25, 2011 · 7 revisions

When you’re modifying an assembly, you usually want to inject code that calls into other assemblies. For instance, when you inject logging code, you’d want to add code that calls into a logger assembly. The process of creating a reference for code that lives outside the assembly you’re working on is called «importing».

References are scoped per ModuleDefinition. All Import methods are thus defined on ModuleDefinition, and are able to work on both the .net runtime type system (System.Type, System.Reflection.MethodBase, System.Reflection.FieldInfo), and the Cecil type system (TypeReference, MethodReference, FieldReference).

The following example shows how to inject a call to Console.WriteLine at the top of the body of a MethodDefinition.

using Mono.Cecil;
using Mono.Cecil.Cil;

// ...

var method = GetMethodDefinition (...);
var il = method.Body.GetILProcessor ();

var ldstr = il.Create (OpCodes.Ldstr, method.Name);
var call = il.Create (OpCodes.Call,
	method.Module.Import (
		typeof (Console).GetMethod ("WriteLine", new [] { typeof (string) })));

il.InsertBefore (method.Body.Instructions [0], ldstr);
il.InsertAfter (method.Body.Instructions [0], call);

Importing gets really necessary whenever you’re adding metadata to the assembly. Let’s add to a module a static class, which will contain a single static method.
var module = GetModuleDefinition (...);

var type = new TypeDefinition (
	"Foo.Bar",
	"Baz",
	TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed,
	module.Import (typeof (object)));

module.Types.Add (type);

var method = new MethodDefinition (
	"Bang",
	MethodAttributes.Public | MethodAttributes.Static,
	module.Import (typeof (void)));

type.Methods.Add (method);

method.Parameters.Add (new ParameterDefinition (module.Import (typeof (string))));

Notice that Import is used to get a TypeReference to System.Object, as the base type of the Foo.Bar.Baz type. It’s also used to set the return type of the Bang method to System.Void, and to add to it a parameter of type System.String.