C# LINQ表达式在哪里扩展

C# LINQ表达式在哪里扩展,c#,linq,lambda,C#,Linq,Lambda,我想知道如何“完成”LINQ到实体的表达式。这就是我想写的: IQueryable<Products> qry = ... qry = ApplyFilter(qry, p => p.Name, "hello"); private IQueryable<Products> ApplyFilter( IQueryable<Products> qry, Expression<Func<Products,

我想知道如何“完成”LINQ到实体的表达式。这就是我想写的:

IQueryable<Products> qry = ...
qry = ApplyFilter(qry, p => p.Name, "hello");

private IQueryable<Products> ApplyFilter(
          IQueryable<Products> qry, 
          Expression<Func<Products,String>> field, 
          String likeFilter)
{
  // ???
  return qry.Where( field.Contains( likeFilter )); 
}
IQueryable qry=。。。
qry=ApplyFilter(qry,p=>p.Name,“hello”);
私人可液化贴花过滤器(
易读的qry,
表达式字段,
字符串(类过滤器)
{
// ???
返回qry.Where(field.Contains(likeFilter));
}

调用语法很重要(需要简单明了),函数参数和函数体是其弱点:(我在lambda函数和表达式方面越来越好,但目前还不够好:(感谢所有的帮助和建议!

因为我现在发现您不想编译表达式,您需要基于提供的表达式构建一个新的更复杂的表达式来检索字段值。我已经冒昧地将解决方案设置为泛型,因为代码不需要
产品
类型:

private IQueryable<T> ApplyFilter<T>(
          IQueryable<T> qry,
          Expression<Func<T,String>> field,
          String likeFilter)
{
  var methodInfo = typeof(String).GetMethod("Contains");
  var methodCallExpression = Expression
    .Call(field.Body, methodInfo, Expression.Constant(likeFilter));
  var predicate = Expression
    .Lambda<Func<T, Boolean>>(methodCallExpression, field.Parameters[0]);
  return qry.Where(predicate);
}
专用IQueryable ApplyFilter(
易读的qry,
表达式字段,
字符串(类过滤器)
{
var methodInfo=typeof(String).GetMethod(“包含”);
var methodCallExpression=表达式
.Call(field.Body、methodInfo、Expression.Constant(likeFilter));
变量谓词=表达式
.Lambda(methodCallExpression,field.Parameters[0]);
返回qry.Where(谓词);
}

如果
字段
表达式是
p=>p.Name
那么
谓词
中的表达式是
p=>p.Name.Contains(likeFilter)
。实体框架能够理解此表达式并将其转换为SQL。

如果将方法设计为通用扩展方法,效果会更好(与其他linq扩展一样)

公共静态类扩展
{
公共静态IQueryable ApplyFilter(此IQueryable qry,Func字段,类似字符串的筛选器)
{
返回qry.Where(x=>field(x).Contains(likeFilter));
}
}
用法:

IQueryable<Product> qry = new List<Product>() 
    { 
        new Product() {Name = "Ball", Category = "Sport"},
        new Product() {Name = "Bag", Category = "Other"},
        new Product() {Name = "Sport bag", Category = "Sport"},
    }.AsQueryable();

var result = qry.ApplyFilter(p => p.Category, "Sport");
IQueryable qry=新列表()
{ 
新产品(){Name=“Ball”,Category=“Sport”},
新产品(){Name=“Bag”,Category=“Other”},
新产品(){Name=“Sport bag”,Category=“Sport”},
}.AsQueryable();
var结果=qry.ApplyFilter(p=>p.类别,“运动”);
另外,您可以将区分大小写的标志变量添加到扩展方法中

编辑- 尝试此修改:

public static IEnumerable<T> ApplyFilter<T>(this IQueryable<T> qry, Func<T, string> field, string likeFilter)
{
    foreach (var item in qry)
    {
        if (field(item).Contains(likeFilter))
        {
            yield return item;
        }
    }
}
公共静态IEnumerable ApplyFilter(此IQueryable qry,Func字段,类似字符串的筛选器)
{
foreach(qry中的var项目)
{
if(字段(项).Contains(likeFilter))
{
收益回报项目;
}
}
}
不幸的是,我不知道这是否打破了IQueryable子句的积累

编辑2

好的,最后我决定实现为构建表达式树,这样我可以确保它将成功地转换为SQL。最终(我希望:D)解决方案:

public static IQueryable<T> ApplyFilter<T>(this IQueryable<T> qry, Expression<Func<T, string>> field, string likeFilter)
{
    var member = field.Body as MemberExpression;
    var propInfo = member.Member as PropertyInfo;

    var param = Expression.Parameter(typeof(T), "x");
    var prop = Expression.Property(param, propInfo);

    var containsMethod = typeof(string).GetMethod("Contains");
    var body = Expression.Call(prop, containsMethod, Expression.Constant(likeFilter));
    var expr = Expression.Lambda<Func<T, bool>>(body, param);

    return qry.Where(expr);
}
公共静态IQueryable ApplyFilter(此IQueryable qry,表达式字段,类似字符串的筛选器)
{
var member=field.Body作为MemberExpression;
var propInfo=member.member作为PropertyInfo;
var param=表达式参数(类型(T),“x”);
var prop=Expression.Property(param,propInfo);
var containsMethod=typeof(string).GetMethod(“Contains”);
var body=Expression.Call(prop,containsMethod,Expression.Constant(likeFilter));
var expr=Expression.Lambda(body,param);
返回qry.Where(expr);
}

Linq查询最终将转换为SQL。如果where子句中有任意函数,则会出现“invoke not supported”(调用不受支持)错误。以下操作是否适用于您

public class Products
{
    public string Name { get; set; }
}


static void Main()
{
    IQueryable<Products> qry = new List<Products> {         
        new Products() {Name = "Football" },
        new Products() {Name = "Baseball" },
        new Products() {Name = "Glove" },
    }.AsQueryable();

    var r = ApplyFilter(qry, p => p.Name.Contains("ball"));
}


private static IQueryable<Products> ApplyFilter(IQueryable<Products> qry, Expression<Func<Products, bool>> predicate)
{
    return qry.Where(predicate);
}
公共类产品
{
公共字符串名称{get;set;}
}
静态void Main()
{
IQueryable qry=新列表{
新产品(){Name=“Football”},
新产品(){Name=“barball”},
新产品(){Name=“手套”},
}.AsQueryable();
var r=ApplyFilter(qry,p=>p.Name.Contains(“ball”);
}
专用静态IQueryable ApplyFilter(IQueryable qry,表达式谓词)
{
返回qry.Where(谓词);
}

ApplyFilter方法不清楚您想做什么。您能提供更多细节吗?这是我通常写的:
Products.Where(p=>p.Name.Contains(“hello”)
,现在我想写
ApplyFilter(Products,p=>p.Name,“hello”)
。整个环境很复杂,这是要解决的根本问题,其他小问题也可以很容易解决。不过,我喜欢这个解决方案,但不幸的是,EF会删除一个异常EntityFramework.SqlServer.dll中发生的“System.NotSupportedException”类型的未处理异常附加信息:LINQ表达式LINQ to Entities中不支持节点类型“Invoke”。我尝试在LINQ to Entities环境中使用它…:(编译与你想要的不是相反吗?
Compile
需要查看
表达式中的内容并将其转换为SQL。编译会打破这一点。我同意。
Compile
将尝试调用存储过程。没错,最后的代码将是泛型的,我尽量简化问题很遗憾,在LINQ to Entities中,此代码也会删除异常:EntityFramework.SqlServer.dll中发生了类型为“System.NotSupportedException”的未处理异常。其他信息:LINQ to Entities中不支持LINQ表达式节点类型“Invoke”:(更新了答案。我用EF测试了它。非常类似于@MartinLiversage的解决方案。似乎也有效!:)谢谢你的时间和耐心!实际上他的解决方案与我的类似,因为他在我之后编辑了他的答案:POhh抱歉:(出于某种原因,我先读了,在你之前:)
public class Products
{
    public string Name { get; set; }
}


static void Main()
{
    IQueryable<Products> qry = new List<Products> {         
        new Products() {Name = "Football" },
        new Products() {Name = "Baseball" },
        new Products() {Name = "Glove" },
    }.AsQueryable();

    var r = ApplyFilter(qry, p => p.Name.Contains("ball"));
}


private static IQueryable<Products> ApplyFilter(IQueryable<Products> qry, Expression<Func<Products, bool>> predicate)
{
    return qry.Where(predicate);
}