lambda表达式从接口转换而来

时间:2017-12-28 17:39:54

标签: c# reflection lambda casting

我有以下界面:

public interface IHasSchoolId
{
    long? SchoolId { get; set; }
}

和以下实体:

public class Student : IHasSchoolId
{
    long? SchoolId { get; set; }
}

然后有以下实体管理器实现空接口IEntityManager<T>

public class HasSchoolIdManager: IEntityManager<IHasSchoolId>
{
    public static Expression<Func<IHasSchoolId, bool>> Filter()
    {
        return x=> x.SchoolId != null; //this is just an example
    }
}

最后我有以下方法:

private Expression<Func<TEntity, bool>> GetFilters<TEntity>()
{
    Expression<Func<TEntity, bool>> result = null;
    var entityManagers = //geting entitymanagers that are assinable to TEntity, like the one above and a lot more like IEntityManager<Student> itself
    foreach (var entityManager in entityManagers)
    {
        var filterMethod = entityManager.GetMethod("Filter");
        if (filterMethod != null)
            result = AndAlso(result, (Expression<Func<TEntity, bool>>) filterMethod.Invoke(null, null)); //this line throws exception
    }
    return result;
}

然后当我调用类似GetFilters<Student>()的方法时,我会得到以下异常:

  

System.InvalidCastException :'无法转换类型为'System.Linq.Expressions.Expression [System.Func [WebCore.Models.Infrastructure.Interfaces.IHasSchoolId,System.Boolean]]'的对象输入'System.Linq.Expressions.Expression [System.Func [WebCore.Models.Student,System.Boolean]]'。'

顺便说一句,这是我的AndAlso方法,它运行良好:

private Expression<Func<T, bool>> AndAlso<T>(
        Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
{
    if (expr1 == null)
        return expr2;
    if (expr2 == null)
        return expr1;
    ParameterExpression param = expr1.Parameters[0];
    if (ReferenceEquals(param, expr2.Parameters[0]))
    {
        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(expr1.Body, expr2.Body), param);
    }
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(
            expr1.Body,
            Expression.Invoke(expr2, param)), param);
}

这是我的空IEntityManager接口:

public interface IEntityManager<T>
{

}

注意:并非我的所有实体都实现了IHasSchoolId接口,还有很多其他接口,这只是一个例子

我认为我的问题是,如何从Expression<Func</*an interface*/, bool>>投射到Expression<Func</*a class that implements that interface*/, bool>> 使用反射,因为你可以看到,我使用反射调用过滤器方法

1 个答案:

答案 0 :(得分:0)

这是我最后做的事情:

Expression<Func<T, bool>> expression = null;
var managers = GetEntityManagers<T>();
foreach (var manager in managers)
{
    var expr2 = manager.GetMethod("Filter")?.Invoke(null, null) as dynamic;
    if (expr2 == null) continue;
    var transformedExpr = Transform<T>(expr2) as Expression<Func<T, bool>>;
    expression = expression == null ? transformedExpr : expression.AndAlso(transformedExpr);
}

这是变换函数:

private class Visitor : ExpressionVisitor
{
    private Expression _parameter;

    public Visitor(Expression parameter)
    {
        _parameter = parameter;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _parameter;
    }
}

private static Expression<Func<T, bool>> Transform<T>(dynamic expression)
{
    ParameterExpression parameter = Expression.Parameter(typeof(T));
    Expression body = new Visitor(parameter).Visit(expression.Body);
    return Expression.Lambda<Func<T, bool>>(body, parameter);
}