1

Although this question is similar to this question, How do I attach a method to a dynamically-created C# type at runtime?, it does not contain the answer I am looknig for.

I am creating a type dynamically, and then saving this in a dynamic assembly DLL, which can be used in another project.

However, I want to "attach" a C# static method to this dynamic type and call it in the constructor. (since this method is a little complicated).

One way this can be done is to write the method in C# in another project, then use reflection in the dynamic type to invoke it. However, this would mean that the dynamic type will have to ship with a second assembly.

Another way would be to create the method dynamically and then write the IL for this. I would like to avoid this, since I think it would take too much effort. Is there a way to take an existing method written in C# and just "copy" it to the dynamic type?

Update

I am currently creating the new type using AssemblyBuilder, and ModuleBuilder.DefineType.

I have already tried grabbing the method body using MethodInfo.GetMethodBody().GetILAsByteArray() and then setting the newly defined method body using MethodBuilder.CreateMethodBody(), but does not work for some reason. I noticed that the IL code is only ~450 bytes, which seems too small for me, because there are several string literals in there that would easily use up this space. I am guessing there is some additional things I need to do to make this work.

As a side question, is it possible to copy an entire type into my dynamic assembly?

Community
  • 1
  • 1
Mas
  • 4,546
  • 5
  • 39
  • 56
  • Does the method you want to attach do anything specific to the newly created Type ? – Yahia Dec 02 '11 at 15:15
  • What are you using to create the dynamic type? Reflection.Emit? – Anton Tykhyy Dec 02 '11 at 15:19
  • The only way this is possible is via a virtual method. That said, calling a virtual method in the constructor is a complete no-no. – leppie Dec 02 '11 at 15:20
  • @AntonTykhyy: The only way to save an assembly is via Reflection.Emit. – leppie Dec 02 '11 at 15:20
  • @leppie: there are also 3rd-party libraries such as Mono.Cecil. With Mono.Cecil it is not difficult to read one assembly, extract the method body (IL instructions + exception blocks + locals signature) and copy it to a method in the new assembly. With Reflection.Emit, I imagine one would need to parse the raw IL to substitute metadata tokens (and import any referenced types, methods etc.) – Anton Tykhyy Dec 02 '11 at 17:09

1 Answers1

1

A little late but I solved this using Expression Trees and compiling them into the MethodBuilder as answered here in response to this SO question. In summary:

Using Expression Trees instead of having to emit raw IL.

var queue = new Queue<Expression>();
var arguments = Expression.Parameter(typeof(string []), "args");

queue.Enqueue(Expression.Call(typeof(Console).GetMethod("WriteLine", new Type [] { })));

var block = Expression.Block(queue);
var lambda = Expression.Lambda<Func<string [], int>>(block, new ParameterExpression [] { arguments });

lambda.CompileToMethod(builderMethod);
// builderMethod is a MethodBuilder instance created earlier.

This is very powerful indeed and definitely suited for situations where micro-perf is not required using ILGenerator.

Community
  • 1
  • 1
Raheel Khan
  • 14,205
  • 13
  • 80
  • 168