Is there any simple way to convert
Expression<Func<TBase,bool>>
to
Expression<Func<T,bool>>
where T is inherited from TBase?
Is there any simple way to convert
Expression<Func<TBase,bool>>
to
Expression<Func<T,bool>>
where T is inherited from TBase?
As long as T derives from TBase, you can directly create an expression of your desired type with the body and parameters of your original expression.
Expression<Func<object, bool>> x = o => o != null;
Expression<Func<string, bool>> y = Expression.Lambda<Func<string, bool>>(x.Body, x.Parameters);
You may have to convert manually. The reason for this is that you're effectively converting to a subset of what it could be. All T
are TBase
, but not all TBase
are T
.
The good news is that you can probably do it using Expression.Invoke, and apply the appropriate cast/conversion to TBase
manually (of course catching any type safety issues).
Edit: I apologize for misunderstanding the direction you wanted to go in. I think simply converting the expression is still your best route either way. It gives you the ability to handle the conversion however you want. Marc Gravell's answer here is the most compact and clear way I've seen to do it.
To make this I wrote ExpressionVisitor with overloading VisitLambda and VisitParameter
Here it is:
public class ConverterExpressionVisitor<TDest> : ExpressionVisitor
{
protected override Expression VisitLambda<T>(Expression<T> node)
{
var readOnlyCollection = node.Parameters.Select(a => Expression.Parameter(typeof(TDest), a.Name));
return Expression.Lambda(node.Body, node.Name, readOnlyCollection);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return Expression.Parameter(typeof(TDest), node.Name);
}
}
public class A { public string S { get; set; } }
public class B : A { }
static void Main(string[] args)
{
Expression<Func<A, bool>> ExpForA = a => a.S.StartsWith("Foo");
Console.WriteLine(ExpForA); // a => a.S.StartsWith("Foo");
var converter = new ConverterExpressionVisitor<B>();
Expression<Func<B, bool>> ExpForB = (Expression<Func<B, bool>>)converter.Visit(ExpForA);
Console.WriteLine(ExpForB); // a => a.S.StartsWith("Foo"); - same as for A but for B
Console.ReadLine();
}