【问题标题】:Converting Where from LINQ clause to dynamic LINQ将 Where 从 LINQ 子句转换为动态 LINQ
【发布时间】:2012-03-21 18:00:08
【问题描述】:

我想离开

        var selectData = (from i in data
                          where i.Name == "Bob1"
                          select i);

        var selectData = (from i in data
                          select i).Where("Name==Bob1");

我尝试了各种方法(AsQueryableWhere<SomeData>),但无法编译第二种形式。

我不太了解 C# 的通用扩展方法。 <Tsource> 对我来说没有意义,所以这可能是问题所在。另外,我不明白为什么当智能感知只显示.Where<>(通用)时我可以输入.Where()。我希望看到第二个 Where 没有通用符号...唉,我没有。

public class SomeData
{
    public string Name { get; set; }
    public string Address { get; set; }
}

更新
关于如何使用 Where() 似乎有些困惑,这很可能是我的错。请参阅related 问题。根据这个答案,where 子句中的属性名称是完全合法的。我需要该属性保持为字符串。如果这意味着需要动态 LINQ,那就这样吧……这就是我所需要的。

【问题讨论】:

  • 这似乎与另一个帖子相似。也许这会有所帮助 [LINQ - 动态 WHERE 子句?][1] [1]:stackoverflow.com/questions/848415/linq-dynamic-where-clause
  • 您需要动态查询您的属性名称吗?你能确认一下吗?
  • 我还是不明白。如果您正在寻找如何进行动态 Linq,那么您在 other question you asked 上已经引用的答案是否也不是这个问题的答案?
  • @Paul Ruane - 我正在尝试让另一个答案起作用。我认为动态 LINQ 只是 .NET OOB 功能的一部分。而且我在做一些语法不正确的事情。显然情况并非如此。
  • @P.Brian.Mackey:我快速阅读了一遍。看来可能是separate download

标签: c# dynamic-linq


【解决方案1】:
var selectData = (from i in data
                  select i).Where(datum => datum.Name == "Bob1");

Where 方法采用委托,而不是字符串,因此您需要传入委托或 lambda。

编辑:根据您对其他答案之一的评论,您将需要使用反射来动态查找属性值。

编辑:看起来您需要为 Dynamic Linq 库单独 download the source code

【讨论】:

  • 如果是这样,请解释这个其他相关答案:stackoverflow.com/questions/9505189/…
  • @P.Brian.Mackey:使用动态 Linq。您当然可以对此进行探索,但这不是您在问题中提出的问题。
  • 那么我是否可以假设动态 LINQ 是我需要下载和参考的附加组件?
  • @P.Brian.Mackey:我不知道,我从未使用过它。在我们发言时,我正在阅读您在其他问题中接受的答案中发布的链接。
【解决方案2】:

在您的帮助下,我成功地实现了功能转换。

  1. 安装 Dynamic LINQ(我使用的是 NUGET。在线搜索 System.Linq.Dynamic)
  2. 添加using System.Linq.Dynamic
  3. 查询应该是格式

        var selectData = (from i in data
                          select i).AsQueryable().Where("Name = @0","Bob1");//@0 is called an identifier.  "Name = Bob1" straight up fails.
    
  4. 安装 ScottGU 的 C# sample library...它会有所帮助。 (VB) (Original Post)

【讨论】:

    【解决方案3】:

    更新

    我最初误解了这个问题;解决问题的方法是下载 Dynamic Linq 并引用它。我将在下面留下我的答案,它解决了您提出的有关通用扩展方法的附带问题。


    var selectData = (from i in data 
        select i).Where(d => d.Name=="Bob1");
    

    但为什么不这样:

    var selectData = data.Where(d => d.Name=="Bob1");
    

    关于 where 的“非通用”版本,没有这样的东西。在上面的调用中,泛型方法的类型参数是隐式的;它是由编译器推断出来的,它编译调用的方式与编译它的方式完全相同:

    var selectData = data.Where<SomeData>(d => d.Name=="Bob1");
    

    也许Where 方法的草图实现将有助于减少您对TSource 参数的混淆:

    public static IEnumerable<TSource> Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        foreach (TSource item in source)
            if (predicate(item))
                yield return item;
    }
    

    TSource 是您要查询的序列的元素类型。也是结果序列的元素类型。

    编译器需要知道类型至少有两个原因:

    首先,我们需要对每个元素调用一个函数来确定是否将其包含在结果序列中。编译器必须知道 predicate 参数的引用对象可以安全地接受 TSource 类型的参数。

    在这种情况下,第二个原因有些微不足道; item 的赋值必须与 TSource 兼容,因为它在 yield return 语句中使用。当然是兼容的,因为是同一类型的。

    【讨论】:

    • 我做不到。我需要将属性作为字符串。
    • “需要将属性作为字符串”是什么意思?属性 一个字符串。你的意思是你想选择属性的值作为一个字符串?如果是这样,该值将是“Bob1”。如果您描述了selectData 的期望值,也许这将有助于澄清。
    • @P.Brian.Mackey 您的意思是要指定在运行时查询的属性,通过将其名称作为字符串传递给方法?
    • @P.Brian.Mackey 好的!在这种情况下,使用扩展方法语法将无济于事。查询理解语法在语义上等同于扩展方法语法;无论如何,编译器都会将查询转换为扩展方法。
    • @P.Brian.Mackey 我添加了一些关于泛型的材料,希望能帮助消除你提到的关于TSource 参数的一些困惑。
    【解决方案4】:

    我相信这就是您正在寻找的:

    http://www.albahari.com/nutshell/predicatebuilder.aspx

    例子

    IQueryable<Product> SearchProducts (params string[] keywords)
    {
      var predicate = PredicateBuilder.False<Product>();
    
      foreach (string keyword in keywords)
      {
        string temp = keyword;
        predicate = predicate.Or (p => p.Description.Contains (temp));
      }
      return dataContext.Products.Where (predicate);
    }
    

    源代码

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Collections.Generic;
    
    public static class PredicateBuilder
    {
      public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
      public static Expression<Func<T, bool>> False<T> () { return f => false; }
    
      public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                          Expression<Func<T, bool>> expr2)
      {
        var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
      }
    
      public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                           Expression<Func<T, bool>> expr2)
      {
        var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
      }
    }
    

    【讨论】:

      【解决方案5】:

      这里有一些简单的代码,使用表达式树来做你想做的事。这仅适用于针对该特定类型的 Property == "..." 查询。你当然可以修改它,让它变得像你需要的那样通用。

          public void Test()
          {
              List<SomeData> data = new List<SomeData>();
              data.Add(new SomeData("Mark", "Ledgewood Drive"));
              data.Add(new SomeData("Tim", "Sumpter Drive"));
              data.Add(new SomeData("Sean", "Leroy Drive"));
              data.Add(new SomeData("Bob", "Wilmington Road"));
              data.Add(new SomeData("Sean", "Sunset Blvd"));
      
              List<SomeData> result = data.Where(BuildExpression("Name", "Mark")).ToList();
              List<SomeData> result2 = data.Where(BuildExpression("Address", "Wilmington Road")).ToList();
          }
      
          private Func<SomeData, bool> BuildExpression(string propertyName, string value)
          {
              ParameterExpression pe = Expression.Parameter(typeof(SomeData), "someData");
              Expression left = Expression.Property(pe, propertyName);
              Expression right = Expression.Constant(value);
              BinaryExpression binary = Expression.Equal(left, right);
              Expression<Func<SomeData, bool>> lambda = Expression.Lambda<Func<SomeData, bool>>(binary, pe);
              return lambda.Compile();
          }
      

      【讨论】:

        猜你喜欢
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多