Daniel Cazzulino's Blog

Go Back to
kzu′s Latest post

Statically-typed reflection with LINQ

Quite some time ago I posted about how to use LINQ to provide a strong-typed reflection API. I used a very old LINQ preview back then.

With .NET 3.5 and C# 3.0 released now, it was time for an update. As part of the update, I also improved the API a little bit. Usage now is:

MethodInfo toString = Reflect<object>.GetMethod(x => x.ToString());

The renamed Reflect<TTarget> class receives the type you want to reflect as a generic parameter. Then you can use GetMethod, GetField or GetProperty.

Other examples:

MethodInfo clone = Reflect<ICloneable>.GetMethod(x => x.Clone());

PropertyInfo prop = Reflect<AppDomain>.GetProperty(x => x.BaseDirectory);

FieldInfo field = Reflect<Mock>.GetField(x => x.PublicField);

Working principle is the same: the lambda you pass to the methods is actually an expression which I analyze to retrieve the underlying reflection object that is already exposed by the LINQ Expression API. For example, once you get to a MethodCallExpression, you can get the method being called through its Method property:


It’s interesting to see how this works actually, and what’s the compiler generating for those lambda expressions invoking methods.

In Reflector, the following C# code:

MethodInfo clone = Reflect<ICloneable>.GetMethod(x => x.Clone());

is decompiled as (indented for readability):

ParameterExpression CS$0$0000;
MethodInfo clone = Reflect<ICloneable>.GetMethod(Expression.Lambda<Action<ICloneable>>(Expression.Call(      CS$0$0000 = Expression.Parameter(typeof(ICloneable), "x"),       (MethodInfo) methodof(ICloneable.Clone), new Expression[0]    ), new ParameterExpression[] { CS$0$0000 }  ));

Note how the MethodInfo is retrieved directly from the interface by using a methodof operator. It’s not a valid C# keyword, but given that Lutz Roeder works for Microsoft (not on the C# team, though), let’s hope it will get eventually in the language :) .

That methodof translation is actually the conversion from the following two IL lines:

L_0017: ldtoken instance object [mscorlib]System.ICloneable::Clone()L_001c: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)

ldtoken is the key there, let’s hope it gets promoted to C# in some way eventually.

Anyway, since I wrote my original article, I realized through Ayende’s blog that you can also do static reflection without LINQ. It only works for methods though, and you cannot use the lambda syntax because it results in method infos that are actually from a compiler-generated type (the one that contains the closures too if any).

As I’m so in love with the lambda syntax, I’ll keep my implementation based on expression trees instead of delegates.

[Update]: superseded by the NETFx Reflector package.