用参数替换Where子句Lambda中的运算符

本文关键字:运算符 Lambda 子句 参数 替换 Where | 更新日期: 2023-09-27 18:24:04

我想用方法中传递的参数替换linq lambda子句中的运算符(==,>=,>…)

方法:

public IEnumerable<Localisation> GetByFiltre(string filter, string valeurDate1)
/*
filter has the value of an operator:
>
==
!=
>=
<=
*/
    DateTime dt = Convert.ToDateTime(valeurDate1);
    var mod = from o in new GpsContext().Locals.Where(loc => loc.Date == dt)

我想用参数筛选器替换子句中的==获得类似的东西

     var mod = from o in new GpsContext().Locals.Where(loc => loc.Date filter dt)

任何人都知道如何让它发挥作用?

用参数替换Where子句Lambda中的运算符

我认为最好用字符串过滤器和相应的委托来制作字典。

class YourClass
{
     static readonly Dictionary<string, Func<DateTime, DateTime, bool>> s_filters = new Dictionary<string, Func<DateTime, DateTime, bool>>
     {
       {  ">", new Func<DateTime, DateTime, bool>((d1, d2) => d1  > d2) }
       { "==", new Func<DateTime, DateTime, bool>((d1, d2) => d1 == d2) }
       { "!=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 != d2) }
       { ">=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 >= d2) }
       { "<=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 <= d2) }
     };
     public IEnumerable<Localisation> GetByFiltre(string filter, string valeurDate1)
     {
        ...
        DateTime dt = Convert.ToDateTime(valeurDate1);
        var filterDelegate = s_filters[filter];
        var mod = from o in new GpsContext().Locals.Where(loc => filterDelegate(loc.Date,dt));
        ...
     }
}

有一个很好的库可以将字符串解析为此处描述的Lamdba表达式

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

并可在此处下载

http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx

它有一个非常好的表达式语法,可以让你表达很多不同的查询和操作。

请注意,根据查询的不同,您可能会失去一些类型安全性。Where操作可以,但编译器无法推断从字符串解析Select lambda的任何类型的投影。这意味着您最终得到的是非泛型IQueryable,而不是泛型类型的IQueryables。有时这是可以的,但它确实会阻止您稍后在查询中使用泛型扩展方法。

编辑以澄清非通用查询操作的情况:库包含一组非通用版本的查询扩展方法,这些方法采用表达式的字符串表示形式,并对非通用IQueryable进行操作。如果你看一下代码,很容易就能知道如果你想要的代码不在那里,该怎么写。例如,我需要做一个非通用的Join,它只花了几个小时。

我找到了一个解决您问题的方法,它的工作原理如下:

var test = dataContext.Interactions.DynamicWhere<Interaction,DateTime>("Created_Month", ExpressionType.LessThan, DateTime.Now);

您可以使用任何ExpressionType-等于、小于、大于等,如果可能的话,它将被转换为T-SQL(因此过滤将在服务器上完成)。它也将在IEnumerables上的内存中工作。

这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace WindowsFormsApplication1
{
    public static class GenericFilterExtension
    {
        public static IQueryable<TRow> DynamicWhere<TRow,TColumn>(this IQueryable<TRow> input, string field, ExpressionType binaryOperator, TColumn value)
        {
            var exp = MakeWhereLambda<TRow, TColumn>(field, binaryOperator, value) as Expression<Func<TRow, bool>>;    
            return input.Where(exp);
        }
        public static IEnumerable<TRow> DynamicWhere<TRow, TColumn>(this IEnumerable<TRow> input, string field, ExpressionType binaryOperator, TColumn value)
        {
            var exp = MakeWhereLambda<TRow, TColumn>(field, binaryOperator, value).Compile() as Func<TRow, bool>;    
            return input.Where(exp);
        }
        private static LambdaExpression MakeWhereLambda<TRow, TColumn>(string field, ExpressionType binaryOperator, TColumn value)
        {
            var param = Expression.Parameter(typeof(TRow), "n");
            var op = Expression.MakeBinary(binaryOperator, Expression.Property(param, field), Expression.Constant(value));    
            return Expression.Lambda(op, new ParameterExpression[] { param });
        }
    }
}

您可以传入作为where子句的函数,例如

public IEnumerable<Localisation> GetByFiltre(Func<IEnumerable<localisation>, IEnumerable<localisation>> whereClause)
{
    /*
    filter has the value of an operator:
    >
    ==
    !=
    >=
    <=
    */
    DateTime dt = Convert.ToDateTime(valeurDate1);
    var mod = whereClause(new GpsContext().Locals);
}

并称之为:

GetByFiltre(f => f.Where(d => d.Date > SomeDate));

过滤器应该包含"=="、">="等?你可以用传统的方法分析过滤字符串:

var mod = from o in new GpsContext().Locals.Where(loc => 
{
    switch(filter)
    {
        case "==":
            return loc.Date == dt;
        case ">=":
            return loc.Date >= dt;
        // ...
    }
})