c# - 动态编译 LINQ 查询以验证字典值

标签 c# .net linq dictionary lambda

让我们假设我们需要查询一个实体列表,我们不知道这个标准是非常动态的,实体里面有字典和简单的字段让它成为下一个实体 - 地址(我只留下一个为简单起见的属性)。

public class Address
{
    #region Public members

    /// <summary>
    /// The extra datafield values
    /// </summary>
    public IDictionary<string, string> DataFieldValues { get; set; }

    public string City { get; set; }

    #endregion
}

现在,如果我们在获得实现时查询名为 City 的固定字段:

   private static Expression<Func<Address, bool>> BuildLambdaForAQueryItem(string caption, string value)
        {
            ParameterExpression param = Expression.Parameter(typeof(Address), caption);
            BinaryExpression body = Expression.Equal(Expression.PropertyOrField(param, caption),
                                                     Expression.Constant(value,
                                                                         typeof(Address).GetProperty(
                                                                             caption).PropertyType));
            return Expression.Lambda<Func<Address, bool>>(body, param);
        }

现在,如果我想查询 DataFieldValue 集合,我也需要编写一个类似的 lambda:

x=>x.DataFieldValues.ContatinsKey(key) && DataFieldValues[key]==value 我用下面的方法得到的几乎是similar但它仍然没有正确应用过滤器:

private static Expression<Func<Address, bool>> BuildLambdaForAnExtraField(PostedQueryItem queryItem)
{
    ParameterExpression dataFields = Expression.Parameter(typeof(Address), "x");
    var dictionaryExpression = Expression.PropertyOrField(dataFields, "DataFieldValues");
    var keyExists = Expression.Call(dictionaryExpression, "ContainsKey", null, Expression.Constant(queryItem.Caption));

    Expression dictionaryAccessExpr = Expression.Property(dictionaryExpression, "Item",
                                                           Expression.Constant(queryItem.Caption));
    var valueCorresponds = Expression.Equal(dictionaryAccessExpr, Expression.Constant(queryItem.Value));

    return Expression.Lambda<Func<Address, bool>>(keyExists, dataFields).And(
      Expression.Lambda<Func<Address, bool>>(valueCorresponds, dataFields));
}

最佳答案

我想你想使用 Expression.AndAlso (短路 AND)在两个有问题的谓词表达式上构建表达式树的主体。

var body = Expression.AndAlso(keyExists, valueCorresponds);
return Expression.Lambda<Func<Address, bool>>(body, dataFields);

编辑:(如果您想坚持使用现有技术)

我的猜测是您的 And 方法是 LINQKit 的扩展方法图书馆。如果是这样,请注意,此扩展涉及使用第一个表达式的参数“调用”右侧表达式作为生成结果的一部分。如果您不能接受这一点(也许是 LINQ 提供程序限制?),您可以使用该库附带的有用的 Expand 扩展来“内联”调用的表达式。

return Expression.Lambda<Func<Address, bool>>(keyExists, dataFields)
                 .And(Expression.Lambda<Func<Address, bool>>(valueCorresponds, dataFields))
                 .Expand();

但在这种情况下,这是大规模的矫枉过正;我的建议是使用我的第一个样本。

关于c# - 动态编译 LINQ 查询以验证字典值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8212642/

相关文章:

c# - 将 XmlSerializer 与根元素中的数组一起使用

c# - Math.Log 的实现方式是否避免了 log(1 + x) 的精度损失?

c# - MS在c#/.net中将MDB Access 到Sqlite

c# - 按属性名称(字符串值)排序列表?

linq - NHibernate 3 使用 SQL Compact 4.0 和 FirstOrDefault() 抛出 NotSupportedException

c# - 如何查找System.Private.CoreLib.ni.dll中发生 'System.Runtime.InteropServices.SEHException'的原因?

c# - 使用委托(delegate)来简化函数调用

c# - 多行文本框到数组 C#

.net - 缺少嵌入互操作类型属性

c# - 如何将具有相同类型项目的列表列表合并为单个项目列表?