【问题标题】:lambda expression cast from interface从接口转换的 lambda 表达式
【发布时间】:2018-06-09 06:21:01
【问题描述】:

我有以下界面:

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&lt;Student&gt;() 之类的方法时,我得到以下异常:

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&lt;Func&lt;/*an interface*/, bool&gt;&gt; 转换为 Expression&lt;Func&lt;/*a class that implements that interface*/, bool&gt;&gt; 使用反射,因为如您所见,我使用反射调用过滤器方法

【问题讨论】:

  • 请出示IEntityManager界面
  • 我不确定您要实现什么,并且您没有显示管理器界面的代码(我知道它是空的,但仍然需要),所以我假设您定义了它与界面。相反,请尝试使管理器接口通用并将其限制为接口,例如public interface IEntityManager&lt;TEntity&gt; where TEntity : IHasSchoolId
  • 请贴出引发异常的代码行。
  • @JohnWu 他已经做到了。方法见代码中的 cmets(需要向右滚动才能看到)。
  • @user4111079 你找到解决方案了吗?我也在搜索完全相同的代码,就像这样public class FilterQueryable { public Expression&lt;Func&lt;IHasCreator, bool&gt;&gt; forCurrentUser; public FilterQueryable(UserValues userValues) { forCurrentUser = p =&gt; p.CreatorId == userValues.Identifier; } }

标签: c# reflection lambda casting


【解决方案1】:

这是我最终所做的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多