I cannot find the way to convert from Expression
What your asking for is very unwise. How would the compiler ever know if T1 is can be converted to T2? Seems like asking for awful run-time errors even if it is possible.*
(*I don't think its possible since you are trying to combine refection with nested generic types.)
It looks like you want to combine 2 expressions - T2
to T1
conversion and than call to expr
with given result.
This question discusses Combining two expressions (Expression<Func<T, bool>>) in general. For your case I think you need Expression.Call to construct conversion expression and than again to call original expression with result of conversion.
Is this what you're looking for? There are two flavors of the method: the first lets you pass in the new input type as an argument; the second lets you pass in the input type as a generic parameter and get a strongly typed LambdaExpression.
public static LambdaExpression ChangeInputType<T, TResult>(Expression<Func<T, TResult>> expression, Type newInputType)
{
if (!typeof(T).IsAssignableFrom(newInputType))
throw new Exception(string.Format("{0} is not assignable from {1}.", typeof(T), newInputType));
var beforeParameter = expression.Parameters.Single();
var afterParameter = Expression.Parameter(newInputType, beforeParameter.Name);
var visitor = new SubstitutionExpressionVisitor(beforeParameter, afterParameter);
return Expression.Lambda(visitor.Visit(expression.Body), afterParameter);
}
public static Expression<Func<T2, TResult>> ChangeInputType<T1, T2, TResult>(Expression<Func<T1, TResult>> expression)
{
if (!typeof(T1).IsAssignableFrom(typeof(T2)))
throw new Exception(string.Format("{0} is not assignable from {1}.", typeof(T1), typeof(T2)));
var beforeParameter = expression.Parameters.Single();
var afterParameter = Expression.Parameter(typeof(T2), beforeParameter.Name);
var visitor = new SubstitutionExpressionVisitor(beforeParameter, afterParameter);
return Expression.Lambda<Func<T2, TResult>>(visitor.Visit(expression.Body), afterParameter);
}
public class SubstitutionExpressionVisitor : ExpressionVisitor
{
private Expression before, after;
public SubstitutionExpressionVisitor(Expression before, Expression after)
{
this.before = before;
this.after = after;
}
public override Expression Visit(Expression node)
{
return node == before ? after : base.Visit(node);
}
}