【问题标题】:LINQ Expression ProblemLINQ 表达式问题
【发布时间】:2011-08-14 11:52:14
【问题描述】:

我有一个让我非常头疼的 Linq 表达式,希望有人能帮我找出我的提供商不喜欢它的原因。

如果我执行以下操作,则效果很好;

Expression<Func<Employee, bool>> expr = e => e.Participant == "Y";
_context.Employees.Where(expr).ToList<IEmployee>();

但是,如果我执行以下操作,我的提供商会不喜欢它。

Expression<Func<IEmployee, bool>> expr = e => e.Participant == "Y";

Expression<Func<Employee, bool>> convertedExpr = ParameterReplacer.Replace
          <Func<IEmployee, bool>, Func<Employee, bool>> 
          (expr,
          expr.Parameters.Single(), 
          Expression.Parameter(typeof(Employee)));

_context.Employees.Where(convertedExpr).ToList<IEmployee>();

我进行转换的原因是我的应用程序的上层只知道接口类型,所以我使用ParameterReplacer(由另一个 SO 成员)。

我比较了有效版本和无效版本之间的 linq 表达式,我能看到的唯一区别是我在 DebugView 属性中看到的参数名称不同。

这是ParameterReplacer的代码;

public static class ParameterReplacer
{
    // Produces an expression identical to 'expression'
    // except with 'source' parameter replaced with 'target' parameter.
    public static Expression<TOutput> Replace<TInput, TOutput>(Expression<TInput> expression, ParameterExpression source, ParameterExpression target)
    { 
        return new ParameterReplacerVisitor<TOutput>(source, target).VisitAndConvert(expression);
    } 

    private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor
    {         
        private ParameterExpression _source;
        private ParameterExpression _target;

        public ParameterReplacerVisitor(ParameterExpression source, ParameterExpression target)
        {             
            _source = source; 
            _target = target;
        } 

        internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root)
        {             
            return (Expression<TOutput>)VisitLambda(root);
        }          

        protected override Expression VisitLambda<T>(Expression<T> node)
        {             
            // Leave all parameters alone except the one we want to replace.
            var parameters = node.Parameters.Select(p => p == _source ? _target : p);
            return Expression.Lambda<TOutput>(Visit(node.Body), parameters);
        }          

        protected override Expression VisitParameter(ParameterExpression node)
        { 
            // Replace the source with the target, visit other params as usual.
            return node == _source ? _target : base.VisitParameter(node);
        }
    } 
}

这是 ParameterReplacer 或我的提供程序的问题吗?谁能帮帮我?

我使用的提供者是 Telerik OpenAccess,它抛出的异常是;

InnerException: System.NullReferenceException Message=对象引用未设置为对象的实例。 来源=Telerik.OpenAccess.35.Extensions 堆栈跟踪: 在 Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQueryImpl(类型 type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean 单,布尔值 checkOid) 在 Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQuery(类型 type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean 单,布尔值 checkOid) 内部异常:

【问题讨论】:

  • 我使用的提供者是 Telerik OpenAccess,它抛出了一个空引用异常。为问题添加了例外。

标签: .net linq lambda


【解决方案1】:

我从未使用过您的提供商,所以我不能确定,但​​考虑到具体情况,我认为这是一个不错的选择:

因为,唯一的区别是第二个表达式中的参数有 null Name 并且您得到的异常是空引用异常,我认为这正是问题所在。尝试将 Name 更改为非空值。

这意味着将新参数的创建更改为:

Expression.Parameter(typeof(Employee), "e")

【讨论】:

  • 太棒了!这正是问题所在。终于,我可以继续前进了。
猜你喜欢
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 2015-08-24
  • 2019-08-09
相关资源
最近更新 更多