将Where从LINQ子句转换为动态LINQ
本文关键字:LINQ 动态 转换 子句 Where | 更新日期: 2023-09-27 18:28:46
我想从
var selectData = (from i in data
where i.Name == "Bob1"
select i);
至
var selectData = (from i in data
select i).Where("Name==Bob1");
我尝试了各种方法(AsQueryable
、Where<SomeData>
),但无法获得要编译的第二个表单。
我对C#的通用扩展方法没有很好的理解。<Tsource>
对我来说没有意义,所以这可能是问题所在。此外,我不明白为什么我可以在intellisense只显示.Where<>
(泛型)的情况下键入.Where()
。我希望看到第二个没有通用符号的Where
。。。唉,我没有。
类
public class SomeData
{
public string Name { get; set; }
public string Address { get; set; }
}
更新
对于如何使用Where(),似乎有一些困惑,这很可能是我的错。请参阅相关问题。基于这个答案,where子句中的财产名称是完全合法的。我需要该属性保持字符串。如果这意味着需要动态LINQ,那就顺其自然吧…这就是我所需要的。
var selectData = (from i in data
select i).Where(datum => datum.Name == "Bob1");
Where
方法接受委托,而不是字符串,因此需要传入委托或lambda。
编辑:根据您对其他答案之一的评论,您需要使用"反射"使属性值查找动态。
编辑:看起来您需要单独下载DynamicLinq库的源代码。
在您的帮助下,我成功地将转换为函数。
- 安装动态LINQ(我使用NUGET.Search在线搜索System.LINQ.Dynamic)
- 添加
using System.Linq.Dynamic
-
查询应采用形式
var selectData = (from i in data select i).AsQueryable().Where("Name = @0","Bob1");//@0 is called an identifier. "Name = Bob1" straight up fails.
-
安装ScottGU的C#示例库。。。这很有帮助。(VB)(原帖)
更新
起初我误解了这个问题;这个问题的解决方案是下载DynamicLinq并引用它。我将在下面留下我的答案,它解决了您关于通用扩展方法的附带问题。
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
语句中使用。当然,它是兼容的,因为它是同一类型的。
我相信这就是您想要的:
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);
}
}
下面是一些简单的代码,使用表达式树来执行您想要的操作。这只适用于针对该特定类型的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();
}