I have a LambdaExpression
which is of type Expression<Func<T, string>>
. The design of the code currently does not allow me to keep T
which means that I am forced to use the slower DynamicInvoke
instead of Invoke
.
Since I know the type of T
I want to convert the expression so that it accepts a T
object, allowing me to use Invoke
. How?
Here's a good start
class Program
{
class MyClass
{
public string MyProperty => "Foo";
}
static LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
{
return expr;
}
static void Main(string[] args)
{
var e1 = GetExpression(t => t.MyProperty);
var e2 = Expression.Lambda<Func<object, object>>(e1, e1.Parameters);
object myClass = new MyClass();
string s1 = (string)e1.Compile().DynamicInvoke(myClass);
object s2 = e2.Compile().Invoke(myClass);
}
}
The non-expression version would look like
Func<object, object> Convert<T>(Func<T, object> f) {
return o => f((T)o);
}
This is what you need to do in the expression version as well. You're right, Expression.Convert
can do that.
Expression<Func<MyClass, object>> e1 = t => t.MyProperty;
var p = Expression.Parameter(typeof(object));
var e2 = Expression.Lambda<Func<object, object>>(
Expression.Invoke(e1, Expression.Convert(p, typeof(MyClass))), p);
Note: as @xanatos rightly notes, for converting e.g. Expression<Func<T, int>>
to Expression<Func<object, object>>
, although C# supports an implicit boxing conversion from int
to object
, expression trees don't. If this is relevant to the question, another Expression.Convert
is needed.