转换从LINQ子句到动态LINQ的位置

时间:2012-03-21 18:00:09

标签: c# dynamic-linq

我想从

开始
        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>对我来说没有意义,所以这可能是问题所在。另外,当intellisense只显示.Where()(通用)时,我不明白为什么我可以输入.Where<>。我希望看到第二个Where没有通用符号......唉,我没有。

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

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

5 个答案:

答案 0 :(得分:2)

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

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

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

编辑:看起来你需要{for} download the source code分别为Dynamic Linq库。

答案 1 :(得分: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

答案 2 :(得分:1)

<强>更新

我最初误解了这个问题;该问题的解决方案是下载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语句中使用。当然它是兼容的,因为它是相同的类型。

答案 3 :(得分:0)

我相信这就是你要找的东西:

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

答案 4 :(得分:0)

这是一些使用表达式树来执行您想要的操作的简单代码。这仅适用于针对该特定类型的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();
    }