2

This is the first time I'm dabbling with generated CIL, so please bear with my ignorance. I'm looking for a simple DynamicMethod that can read the fields of a POCO, and fill them into an object[]. No type conversion is necessary. I've put together everything I can, can you help complete it?

Type t = typeof(POCO);

DynamicMethod dm = new DynamicMethod("Get" + memberName,typeof(MemberType), new Type[] { objectType }, objectType);
ILGenerator il = dm.GetILGenerator();

// Load the instance of the object (argument 0) onto the stack
il.Emit(OpCodes.Ldarg_0);

// get fields
FieldInfo[] fields = t.GetFields();

// how do I create an array (object[]) at this point?

// per field
foreach (var pi in fields) {

    // Load the value of the object's field (fi) onto the stack
    il.Emit(OpCodes.Ldfld, fi);

    // how do I add it into the array?

}

// how do I push the array onto the stack?

// return the array
il.Emit(OpCodes.Ret);
Robin Rodricks
  • 110,798
  • 141
  • 398
  • 607
  • 1
    There is a simple solution using expression trees, that makes you a compiled lambda. Would you be interested in it, or are you looking specifically for an emit solution? – Sergey Kalinichenko Feb 23 '13 at 13:15
  • 1
    If you want to know how to do something in IL, write the same code in C# and look the the generated IL. – svick Feb 23 '13 at 13:17
  • 1
    @Geotarget I think you are confusing LINQ and Linq expression trees. Compiled expression trees are equally as fast as the code that you emit manually. – Sergey Kalinichenko Feb 23 '13 at 13:19
  • 1
    @Geotarget They're not. If you compile a lambda expression, you will get a delegate, exactly the same as if you used `DynamicMethod`. – svick Feb 23 '13 at 13:19
  • @dasblinkenlight - Add your answer. Some help is better than none. – Robin Rodricks Feb 23 '13 at 13:33

1 Answers1

3

You can use this code to generate a compiled lambda expression.

public static Func<T, object[]> MakeFieldGetter<T>() {
    var arg = Expression.Parameter(typeof(T), "arg");
    var body = Expression.NewArrayInit(
        typeof(object)
    ,   typeof(T).GetFields().Select(f => (Expression)Expression.Convert(Expression.Field(arg, f), typeof(object)))
    );
   return (Func<T, object[]>)Expression
        .Lambda(typeof(Func<T, object[]>), body, arg)
        .Compile();
}

This is equivalent to the following manually written code:

object[] GetFields(MyClass arg) {
    return new object[] {
        // The list of fields is generated through reflection
        // at the time of building the lambda. There is no reflection calls
        // inside the working lambda, though: the field list is "baked into"
        // the expression as if it were hard-coded manually.
        (object)arg.Field1
    ,   (object)arg.Field2
    ,   (object)arg.Field3
    };
}

This code also produces IL, but instead of you writing it manually, it lets Lambda's Compile method do it for your.

Here is a working demo on ideone.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523