Converting a .Net Func<T> to a .Net Expression<Func<T>>

converting a .net Func T to a .net Expression Func T

Ooh, it's not easy at all. Func<T> represents a generic delegate and not an expression. If there's any way you could do so (due to optimizations and other things done by the compiler, some data might be thrown away, so it might be impossible to get the original expression back), it'd be disassembling the IL on the fly and inferring the expression (which is by no means easy). Treating lambda expressions as data (Expression<Func<T>>) is a magic done by the compiler (basically the compiler builds an expression tree in code instead of compiling it to IL).

Related fact

This is why languages that push lambdas to the extreme (like Lisp) are often easier to implement as interpreters. In those languages, code and data are essentially the same thing (even at run time), but our chip cannot understand that form of code, so we have to emulate such a machine by building an interpreter on top of it that understands it (the choice made by Lisp like languages) or sacrificing the power (code will no longer be exactly equal to data) to some extent (the choice made by C#). In C#, the compiler gives the illusion of treating code as data by allowing lambdas to be interpreted as code (Func<T>) and data (Expression<Func<T>>) at compile time.

How to convert Func T,bool to Expression Func T,bool

Try this:

Func<MyClass, bool> func = x=>Id == 5;
Expression<Func<MyClass, bool>> expr = mc => func(mc);

Create Expression from Func

You can not recreate an expression based on a method since an expression needs to know the original statements, not IL. You can however create an Expresson which makes a method call to your func like:

Func<int> func = () => 1;
Expression<Func<int>> expression = Expression.Lambda<Func<int>>(Expression.Call(func.Method));

Note however that systems like EF can't really work with this

Convert Expression Func T, U to Expression Func object, object

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.

How to convert LambdaExpression to Expression Func T,bool in C#

The ExpressionHelper.GetLambda<T, bool> method used to obtain the lambda expression hides its actual type, which is the desired Expression<Func<T, bool>>, so all you need is to use a cast operator:

return (Expression<Func<T, bool>>)lambdaExpression;

Or better, either change the result type of ExpressionHelper.GetLambda<TSource, TDest> to Expression<Func<TSource, TDest>>, or don't use that helper method - when you know the generic type arguments at compile time, simply use one if the generic Expression.Lambda methods (ExpressionHelper.GetLambda<TSource, TDest> seems to be the equivalent of Expression.Lambda<Func<TSource, TDest>>), e.g.

var lambdaExpression = Expression.Lambda<Func<T, bool>>(parameterExpression, finalExpression);

Convert Expression to Expression Func T, bool

Yes; just call Expression.Lambda<Func<T, bool>>(..., parameter), where ... is an expression composed of the expressions you want to combine.

You'd probably want list.Aggregate(Expressions.AndAlso).

If your expressions don't all share the same ParameterExpression, you'll need to rewrite them to do so. (use ExpressionVisitor)

How to cast Expression Func T, DateTime to Expression Func T, object

You can't just cast between them, as they're not the same kind of thing. However, you can effectively add a conversion within the expression tree:

using System;
using System.Linq.Expressions;

class Test
{
// This is the method you want, I think
static Expression<Func<TInput,object>> AddBox<TInput, TOutput>
(Expression<Func<TInput, TOutput>> expression)
{
// Add the boxing operation, but get a weakly typed expression
Expression converted = Expression.Convert
(expression.Body, typeof(object));
// Use Expression.Lambda to get back to strong typing
return Expression.Lambda<Func<TInput,object>>
(converted, expression.Parameters);
}

// Just a simple demo
static void Main()
{
Expression<Func<string, DateTime>> x = text => DateTime.Now;
var y = AddBox(x);
object dt = y.Compile()("hi");
Console.WriteLine(dt);
}
}


Related Topics



Leave a reply



Submit