Converting an Interface Expression to a Concrete Expression
I had a case recently where I needed to convert a LINQ expression of the type of an interface and I needed to convert it to be based on a concrete implementation of that interface. I came up with the following solution, using an ExpressionVisitor and a simple helper method.
First, the helper method in a static class.
internal static Expression<Func<TConcrete, bool>> ConvertToConcreteExpression<TConcrete, TInterface>( Expression<Func<TInterface, bool>> interfaceExpression)
{
if (!typeof(TInterface).IsAssignableFrom(typeof(TConcrete)))
{
throw new Exception("TInterface must be assignable from TConcrete to convert an expression.");
}
return TransformVisitor<TConcrete, TInterface>.Transform(interfaceExpression);
}
Here is the TransformVisitor class.
internal class TransformVisitor<TConcrete, TInterface> : ExpressionVisitor
{
private readonly ParameterExpression _param = Expression.Parameter(typeof(TConcrete), "param_0");
public static Expression<Func<TConcrete, bool>> Transform(Expression expression)
{
var visitor = new TransformVisitor<TConcrete, TInterface>();
var newLambda = (Expression<Func<TConcrete, bool>>)visitor.Visit(expression);
return newLambda;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
if (typeof(T).IsAssignableFrom(typeof(Func<TInterface, bool>)))
{
return Expression.Lambda<Func<TConcrete, bool>>(
Visit(node.Body),
_param
);
}
return base.VisitLambda(node);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.DeclaringType.IsAssignableFrom(typeof(TInterface)))
{
return Expression.MakeMemberAccess(
Visit(node.Expression),
typeof(TConcrete).GetProperty(node.Member.Name));
}
return base.VisitMember(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type.IsAssignableFrom(typeof(TInterface)))
{
return _param;
}
return base.VisitParameter(node);
}
}
Comments