views:

108

answers:

3

I need to dynamically generate some types. The generated type has several methods, constructors, implements an interface and defines the static constructor. Is there a tool that can help with the task?

I am aware of this plugin for Reflector, yet it is only useful on the method level, while I have to generate a whole type.

There is Run#, but it is in pre-alpha and besides, I would like a standalone tool to work in offline mode, so that I can copy-paste the reflection.emit instructions into the production code.

Thanks.

+2  A: 

Yes!

There's the System.Linq.Expressions namespace (in .NET 3.5) that greatly simplifies generating code on the fly, by using abstract expression trees instead of raw IL.

Here's an example I've stolen from the MSDN Expression Trees page, just to demonstrate its power:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

You can't create types though, only functions, so if you want to create whole classes, you will have to combine this with Reflection.Emit unfortunately.

DrJokepu
Is it possible to combine this with Reflection.Emit?
SLaks
SLaks: Yes, for example, you create your type in Reflection.Emit, get a MethodBuilder to build your method and then you emit a call to your compiled expression tree with ILGenerator of the method. There might be simple ways to do that, but this should work as well.
DrJokepu
+2  A: 

Well, personally I have created extension methods on the ILGenerator class with the same names as the opcodes, with the right parameters, so that I don't have to look up the documentation all the time. These extension methods also return the generator object it was invoked on, so I can do call chaining.

For instance, to implement a ToString method, I could do this:

var il = method.GetILGenerator();
il
    .ldarg_0()
    .ldfld(nameField)
    .ret();

I've also created a similar class, named IL, that has methods that return an IL.Element object, which I can collect into a collection or similar, manipulate, etc. before finally emitting the code. This allows me to create "code producers" and not just "code emitters". Subtle difference, but I've found the "give me the code I can emit" has been more useful than "emit the code into this ILGenerator".

Thus, I could do this:

IL.Element[] il = new IL.Element[] {
    IL.ldarg_0(),
    IL.ldfld(nameField),
    IL.ret()
};

and then:

method.GetILGenerator.Emit(il); // also an extension method

Of course, I've added some extra extension methods that makes it easier for me to emit code as well, such as "call_smart", that figures out which of the call instructions to emit based on the type of method (static, virtual, etc.).

Other than that, I don't know of any other tools, so perhaps I didn't really answer your question.

My code is available, if you want to look at it. Leave a comment, and I'll edit the answer and dig up a repository url for you.

Lasse V. Karlsen
Thanks, but your examples show that you have a good knowledge of IL. This is reflected in the API of your extension methods. I do not have that good control of IL. I need something of a higher level, like Reflection.Emit plugin for Reflector only "on steroids".
mark
Ah, I see. Ok, sorry, can't help you there, but look at Expression support in .NET 4.0. In 3.5, you're limited to what you're allowed to generate, but in 4.0, the classes have been updated to support creating almost any kind of code.
Lasse V. Karlsen
Also, I can recommend a good book: Expert IL Assembler 2.0 (http://www.amazon.com/Expert-NET-2-0-IL-Assembler/dp/1590596463).
Lasse V. Karlsen
+1  A: 

I like the reflection emit language plug in for Reflector. This allows you to decomplie code you know and see the SRE code needed to make it, extremely useful.

http://www.codeplex.com/wikipage?ProjectName=reflectoraddins&amp;title=ReflectionEmitLanguage&amp;referringTitle=Home

D.R. Payne
Thanks Payne, I use it all the time. I was thinking of something more high level.
mark