Lambda表达式从接口转换

3

我有以下接口:

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</*一个接口*/, bool>> 强制转换为 Expression<Func</*实现该接口的类*/, bool>>, 使用反射调用过滤器方法,因为你可以看到,我正在使用反射调用过滤器方法。


1
请展示IEntityManager接口。 - codejockie
我不确定你试图达到什么目的,而且你没有展示管理器接口的代码(我知道它是空的,但仍然是必需的),因此我假设你使用了接口来定义它。相反,尝试将管理器接口设置为通用型,并将其限制为接口,就像这样public interface IEntityManager<TEntity> where TEntity : IHasSchoolId - Racil Hilan
请发布抛出异常的代码行。 - John Wu
@JohnWu 他已经完成了。请查看方法的代码注释(您需要向右滚动才能看到它)。 - Racil Hilan
@user4111079 你找到解决方案了吗?我也在寻找完全相同的东西。 我的代码大致如下: { public Expression> forCurrentUser; public FilterQueryable(UserValues userValues) { forCurrentUser = p => p.CreatorId == userValues.Identifier; } }``` - flieks
1个回答

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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接