Wayne Molina
Wayne Molina

Reputation: 19586

How to use a dynamically-determined Type as parameter to a Lambda<Func<>>?

I am dynamically creating a Lambda expression (based on user input but at the moment using dummy values for a proof-of-concept) for a type which I will only know at runtime. I therefore need to pass the T portion of the Func<T,TResult> as a dynamic type, since I won't know the type until runtime (TResult will always be a bool).

It seems that I cannot pass in a Type variable or use typeof with generics. Basically I'm trying to do something like this:

// (f => f.Baz == 1)
Type theType = Type.GetType("Foo");
ParameterExpression pe = Expression.Parameter(theType, "f");
Expression left = Expression.Property(pe, theType.GetProperty("Baz"));
Expression right = Expression.Constant(1);
Expression expr = Expression.Equal(left, right);
// This works fine but uses a hard-coded type, which I won't know until runtime:
// var lambda = Expression.Lambda<Func<Foo,bool>>(expr, new ParameterExpression[] { pe }).Compile();
var lambda = Expression.Lambda<Func<theType, bool>>(expr, new ParameterExpression[] { pe }).Compile();

However, I cannot use the variable theType as the T portion of the Func. How can I fix this?

Upvotes: 0

Views: 351

Answers (1)

xanatos
xanatos

Reputation: 111840

No you can't.

For example, in C#, you can't:

Type t = typeof(int);
List<t> list = new List<t>(); 

or

object list = new List<t>(); 

Unless you use reflection, but then you have to put the list in an object, and you can use it only through reflection.

So if you want you can save your Func<> in an object (or a dynamic) but nothing more.

What you COULD do is always return Func<object, bool> and cast the object to the desidered type IN the lambda function (so use a Expression.Convert(pe, theType));

Or you could use the dynamic:

// lambda == Func<Foo, bool>
dynamic lamdba = Expression.Lambda(expr, new ParameterExpression[] { pe }).Compile();

bool res = lambda(myvalue);

or

// lambda == Func<Foo, bool>
Delegate lamdba = Expression.Lambda(expr, new ParameterExpression[] { pe }).Compile();
bool res = (bool)lambda2.DynamicInvoke(t);

To be taken "not as real" some benchmarks (in StopWatch.Ticks, look at them only for proportions) (Release Mode + Start Without Debugging + some useless cycles so that they are "hot"):

  236384685 dynamic
   56773593 Func<object, bool> + cast
10556024247 DynamicInvoke

as a note, Func<Foo, bool> has the same speed, so there isn't any speed lost in the extra cast.

You can see the code here http://ideone.com/qhnVP3

Upvotes: 1

Related Questions