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
How to Get Text Between Nested Parentheses
How to Clear Browser Cache on Browser Back Button Click in MVC4
Fill Panel with Gradient in Three Colors
Selenium: Drag and Drop from File System to Webdriver
What's the Max Items in a List<T>
Differencebetween .Equals and ==
How to Center Your Main Window in Wpf
Will Using Linq to SQL Help Prevent SQL Injection
Programmatic Way to Get All the Available Languages (In Satellite Assemblies)
How to Secure Passwords Stored Inside Web.Config
Apiresource VS APIscope VS Identityresource
Why Is Parallel.Foreach Much Faster Then Asparallel().Forall() Even Though Msdn Suggests Otherwise