Wednesday, June 04, 2008 2:33 AM bart

Dealing with anonymous types in Reflection.Emit

A few days ago I got an interesting question from one of my blog readers. During my blogging battle with pattern matching, I mentioned the concept of compiling expression tree lamdas on the fly to IL-code. This is actually one of the core parts of the System.Linq.Expressions implementation when expressions are getting compiled using a call to Compile. However, in cases such as pattern matching you might want to emit your own IL-code to control the way e.g. a pattern match with multiple match clauses and types checks gets emitted into a multi-branch if-else if-else statement underneath the covers (remember only the surface of a functional pattern match needs to be functional, we're still dealing with von Neumann machines that don't have intrinsic knowledge of lambda calculus - it would be a nice thing to have some LISC or FISC instruction set though targeted at some typical tricks employed by functional languages, but we're getting off the topic now). When analyzing such an expression tree and allowing type congruential checks in the matcher, you'll be faced with end-users passing in lambdas like this:

(int age) => new { Name = "Bart", Age = age }

which obviously means we want objects that take the shape (string Name, int Age) where Name == "Bart" and selecting Age from it, passing it in to the pattern match body. Now, instead of doing a "duck type style" of object shape check you just might want to do a strict type check first and you might need to instantiate such an anonymous object deep in your code stack. If you'd write something like the below (greatly simplified sample) things won't work as expected:

using System;
using System.Reflection.Emit;

delegate void Foo();

class Skip
{
    static void Main()
    {
        var anon = new { Bar = true };

        DynamicMethod method = new DynamicMethod("MyLambda", typeof(void), new Type[] { });
        ILGenerator ilgen = method.GetILGenerator();
        ilgen.Emit(OpCodes.Ldc_I4_1);
        ilgen.Emit(OpCodes.Newobj, anon.GetType().GetConstructor(new Type[] { typeof(bool) }));
        ilgen.Emit(OpCodes.Pop);
        ilgen.Emit(OpCodes.Ret);

        Foo a = (Foo)method.CreateDelegate(typeof(Foo));
        a();
    }
}

Actually this would fail to execute with an exception like the following:

Unhandled Exception: System.MethodAccessException: <>f__AnonymousType0`1..ctor(Boolean)
   at MyLambda()
   at Skip.Main() 

The reason here is the jitter enforces visibility rules unless - and this is new in .NET Framework 3.5 - you explicitly opt-out from it using the "skipVisibilityChecks" parameter to the DynamicMethod constructor:

DynamicMethod method = new DynamicMethod("MyLambda", typeof(void), new Type[] { }, true); 

Because this is a convoluted sample, you can tell it works fine if it just returns silently :-).

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: , ,

Comments

No Comments