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

时间:2012-02-09 08:45:19

标签: c# linq lambda

我想在linq lambda的子句中使用方法

中传递的参数替换operator(==,> =,> ...)

方法:

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)

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

5 个答案:

答案 0 :(得分:3)

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

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

        ...
     }
}

答案 1 :(得分:1)

有一个很好的库可以将字符串解析为此处描述的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

它具有非常好的表达式语法,可以让您表达相当多的不同查询和操作。

请注意,根据查询,您可能会失去某些类型的安全性。在操作正常的情况下,编译器无法推断出从字符串中解析Select lambda的任何类型的投影。这种情况最终会导致非通用的IQueryables,而不是一般类型的IQueryables。有时这是可以的,但它确实阻止您稍后在查询中使用通用扩展方法。

编辑以阐明非通用查询操作的情况:该库包含一组非泛型版本的查询扩展方法,这些方法采用表达式的字符串表示形式并在非泛型IQueryable上运行。如果您查看代码,如果您想要的那个代码不存在,很容易看到如何编写这些代码。例如,我需要做一个非泛型加入,它只花了几个小时。

答案 2 :(得分:1)

我发现问题的解决方案是这样的:

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

答案 3 :(得分:0)

你可以传入你的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));

答案 4 :(得分:-1)

过滤器应包含“==”,“&gt; =”等?您可以用传统方式分析过滤字符串:

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