How to Cast Expression<Func<T, Datetime>> to Expression<Func<T, Object>>

How to cast ExpressionFuncT, DateTime to ExpressionFuncT, 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);
}
}

Faster way to cast a FuncT, T2 to FuncT, object?

As you know, you can obtain a MethodInfo from PropertyInfo.GetGetMethod(). From that, you can use the following to get a Func<object, object> to retrieve that property. By a similar method, you could return a strongly-typed Func<TObject, TResult>. For any given MethodInfo, you should cache the results of this call if you need it more than once since this method is at least an order of magnitude more expensive than calling the resulting delegate.

private static Func<object, object> BuildAccessor(MethodInfo method)
{
ParameterExpression obj = Expression.Parameter(typeof(object), "obj");

Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);

return expr.Compile();
}

Convert Expression to ExpressionFuncT, 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)

Convert ExpressionFuncT, TProperty to ExpressionFuncobject, object and vice versa

You were correct that you need to use an ExpressionVisitor and ExpressionConvert.

Here are the two methods that you asked for (as well as some support methods):

public Expression<Func<object, object>> ConvertToObject<TParm, TReturn>(Expression<Func<TParm, TReturn>> input)
{
var parm = Expression.Parameter(typeof(object));
var castParm = Expression.Convert(parm, typeof(TParm));
var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
body = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<object, object>>(body, parm);
}

public Expression<Func<TParm, TReturn>> ConvertBack<TParm, TReturn>(Expression<Func<object, object>> input)
{
var parm = Expression.Parameter(typeof(TParm));
var castParm = Expression.Convert(parm, typeof(object));
var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
body = Expression.Convert(body, typeof(TReturn));
return Expression.Lambda<Func<TParm, TReturn>>(body, parm);
}

Expression ReplaceExpression(Expression body, Expression source, Expression dest)
{
var replacer = new ExpressionReplacer(source, dest);
return replacer.Visit(body);
}

public class ExpressionReplacer : ExpressionVisitor
{
Expression _source;
Expression _dest;

public ExpressionReplacer(Expression source, Expression dest)
{
_source = source;
_dest = dest;
}

public override Expression Visit(Expression node)
{
if (node == _source)
return _dest;

return base.Visit(node);
}
}

Sample usage:

Expression<Func<Customer, string>> expression = c => c.Name;
var convertedExpression = ConvertToObject<Customer, string>(expression);
var backExpression = ConvertBack<Customer, string>(convertedExpression);

Of course we can replace the original two methods with one method with more type parameters:

public Expression<Func<TTargetParm, TTargetReturn>> ConvertGeneric<TParm, TReturn, TTargetParm, TTargetReturn>(Expression<Func<TParm, TReturn>> input)
{
var parm = Expression.Parameter(typeof(TTargetParm));
var castParm = Expression.Convert(parm, typeof(TParm));
var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
body = Expression.Convert(body, typeof(TTargetReturn));
return Expression.Lambda<Func<TTargetParm, TTargetReturn>>(body, parm);
}

Sample usage:

Expression<Func<Customer, string>> expression = c => c.Name;
var convertedExpression = ConvertGeneric<Customer, string, object, object>(expression);
var backExpression = ConvertGeneric<object, object, Customer, string>(convertedExpression);

How to convert a LambdaExpression to typed ExpressionFuncT, T

var typedExpression =
(Func<T, bool>)Expression.Lambda(funcType, itemPredicate, parameter); //Fails

This is not surprising, as you have to Compile a LambdaExpression in order to get an actual delegate that can be invoked (which is what Func<T, bool> is).

So this would work, but I 'm not sure if it is what you need:

// This is no longer an expression and cannot be used with IQueryable
var myDelegate =
(Func<T, bool>)
Expression.Lambda(funcType, itemPredicate, parameter).Compile();

If you are not looking to compile the expression but instead to move an expression tree around, then the solution is to instead cast to an Expression<Func<T, bool>>:

var typedExpression = (Expression<Func<T, bool>>) 
Expression.Lambda(funcType, itemPredicate, parameter);

How do I convert ExpressionFuncT, object to ExpressionFuncT, bool?

Assuming that fieldExpression is something like (T e) => e.Field I concluded that you want find in DB record with same value in Field column.

Try this:

foreach (T inputRecord in input)
{
object fieldObject = fieldDelegate.Invoke(inputRecord);

ParameterExpression p = fieldExpression.Parameters.First();
// Equivalent to x => x.Field == fieldObject
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(
// input.Field == fieldObject
Expression.Equal(
// input.Field
fieldExpression.Body,
// constant from fieldObject
Expression.Constant(fieldObject)
),
new []{ p }
);

T dataRecord = dbSet.SingleOrDefault(predicate);

if (dataRecord != null)
{
inputRecord.CreatedOn = dataRecord.CreatedOn;
}
}

I create totally new predicate in each loop run by taking fieldExpression body and pass it to SingleOrDefault invocation.



Related Topics



Leave a reply



Submit