Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# IQueryable扩展:创建lambda表达式以查询列中的关键字_C#_Lambda_Extension Methods - Fatal编程技术网

C# IQueryable扩展:创建lambda表达式以查询列中的关键字

C# IQueryable扩展:创建lambda表达式以查询列中的关键字,c#,lambda,extension-methods,C#,Lambda,Extension Methods,我从本例中的IQueryable扩展方法开始 我认为我需要的是一个IQueryable扩展方法,方法签名如下: public static IQueryable<T> Where<T>(this IQueryable<T> source, string columnName, string keyword) 使用上面的CodePlex示例,我想我理解他是如何让OrderBy方法工作的,但是我的问题似乎有点复杂,我不知道如何让ContainesKeyword部

我从本例中的IQueryable扩展方法开始

我认为我需要的是一个IQueryable扩展方法,方法签名如下:

public static IQueryable<T> Where<T>(this IQueryable<T> source, string columnName, string keyword)
使用上面的CodePlex示例,我想我理解他是如何让OrderBy方法工作的,但是我的问题似乎有点复杂,我不知道如何让ContainesKeyword部分工作

提前感谢,

-

更新:9/13/2010太平洋标准时间下午6:26

我原以为下面的方法可行,但最终得到了NotSupportedException LINQ表达式节点类型“Invoke”在LINQ to实体中不受支持。当我通过Count执行表达式时。有什么想法吗

    public static IQueryable<T> Where<T>(this IQueryable<T> source, string columnName, string keyword)
    {
        var type = typeof(T);
        var property = type.GetProperty(columnName);
        if (property.PropertyType == typeof(string))
        {
            var parameter = Expression.Parameter(type, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var sel = Expression.Lambda<Func<T, string>>(propertyAccess, parameter);
            var compiledSel = sel.Compile();
            return source.Where(item => compiledSel(item).Contains(keyword));
        }
        else
        {
            return source;
        }
    }
.Containskeyword部分在您的示例中完全正确

是p.ColumnName部分会引起麻烦

现在,有很多方法可以做到这一点,通常涉及到反思或表达,这两种方法都不是特别有效

这里的问题是,通过将列名作为字符串传递,您正在做的就是撤销LINQ发明时允许的事情

然而,除此之外,可能还有更好的方法来完成你的总体任务

那么,让我们看看其他方法:

你想说:

   var selector = new Selector("Column1", "keyword");
   mylist.Where(item => selector(item));
而且它相当于

    mylist.Where(item=> item.Column1.Contains("keyword"));
我们一起去怎么样

   Func<MyClass, string> selector = i => i.Column1;
   mylist.Where(item => selector(item).Contains("keyword"));

这些可以很容易地扩展为备选方案:

   Func<MyClass, string> selector;
   if (option == 1)
        selector = i => i.Column1;
   else
        selector = i => i.Column2;
   mylist.Where(item => selector(item).Contains("keyword"));
.Containskeyword部分在您的示例中完全正确

是p.ColumnName部分会引起麻烦

现在,有很多方法可以做到这一点,通常涉及到反思或表达,这两种方法都不是特别有效

这里的问题是,通过将列名作为字符串传递,您正在做的就是撤销LINQ发明时允许的事情

然而,除此之外,可能还有更好的方法来完成你的总体任务

那么,让我们看看其他方法:

你想说:

   var selector = new Selector("Column1", "keyword");
   mylist.Where(item => selector(item));
而且它相当于

    mylist.Where(item=> item.Column1.Contains("keyword"));
我们一起去怎么样

   Func<MyClass, string> selector = i => i.Column1;
   mylist.Where(item => selector(item).Contains("keyword"));

这些可以很容易地扩展为备选方案:

   Func<MyClass, string> selector;
   if (option == 1)
        selector = i => i.Column1;
   else
        selector = i => i.Column2;
   mylist.Where(item => selector(item).Contains("keyword"));

请参见,在泛型中,对象的类型是动态工作的。因此,当p.ColumnName作为字符串时,将执行字符串的Contains

通常,对于您指定的任何lambda表达式,它都会将对象解析为表达式,并最终在运行时生成输出

如果你看到我的帖子:
你会明白它实际上是如何工作的

请参见,在泛型中,对象的类型是动态工作的。因此,当p.ColumnName作为字符串时,将执行字符串的Contains

通常,对于您指定的任何lambda表达式,它都会将对象解析为表达式,并最终在运行时生成输出

如果你看到我的帖子:
你会明白它实际上是如何工作的

好吧,几年后,如果有人还需要这个,这里就是:

    public static IQueryable<T> Has<T>(this IQueryable<T> source, string propertyName, string keyword)
    {
        if (source == null || propertyName.IsNull() || keyword.IsNull())
        {
            return source;
        }
        keyword = keyword.ToLower();

        var parameter = Expression.Parameter(source.ElementType, String.Empty);
        var property = Expression.Property(parameter, propertyName);

        var CONTAINS_METHOD = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var TO_LOWER_METHOD = typeof(string).GetMethod("ToLower", new Type[] { });

        var toLowerExpression = Expression.Call(property, TO_LOWER_METHOD);
        var termConstant = Expression.Constant(keyword, typeof(string));
        var containsExpression = Expression.Call(toLowerExpression, CONTAINS_METHOD, termConstant);

        var predicate = Expression.Lambda<Func<T, bool>>(containsExpression, parameter);

        var methodCallExpression = Expression.Call(typeof(Queryable), "Where",
                                    new Type[] { source.ElementType },
                                    source.Expression, Expression.Quote(predicate));

        return source.Provider.CreateQuery<T>(methodCallExpression);
    }
您还可以连接,使其更具表现力:

filtered = filtered.AsQueryable().Has("Name", strName).Has("City", strCity).Has("State", strState);
顺便说一下,附加到字符串的IsNull只是另一种简单的扩展方法:

    public static Boolean IsNull(this string str)
    {
        return string.IsNullOrEmpty(str);
    }

好吧,几年后,如果有人还需要这个,这里是:

    public static IQueryable<T> Has<T>(this IQueryable<T> source, string propertyName, string keyword)
    {
        if (source == null || propertyName.IsNull() || keyword.IsNull())
        {
            return source;
        }
        keyword = keyword.ToLower();

        var parameter = Expression.Parameter(source.ElementType, String.Empty);
        var property = Expression.Property(parameter, propertyName);

        var CONTAINS_METHOD = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var TO_LOWER_METHOD = typeof(string).GetMethod("ToLower", new Type[] { });

        var toLowerExpression = Expression.Call(property, TO_LOWER_METHOD);
        var termConstant = Expression.Constant(keyword, typeof(string));
        var containsExpression = Expression.Call(toLowerExpression, CONTAINS_METHOD, termConstant);

        var predicate = Expression.Lambda<Func<T, bool>>(containsExpression, parameter);

        var methodCallExpression = Expression.Call(typeof(Queryable), "Where",
                                    new Type[] { source.ElementType },
                                    source.Expression, Expression.Quote(predicate));

        return source.Provider.CreateQuery<T>(methodCallExpression);
    }
您还可以连接,使其更具表现力:

filtered = filtered.AsQueryable().Has("Name", strName).Has("City", strCity).Has("State", strState);
顺便说一下,附加到字符串的IsNull只是另一种简单的扩展方法:

    public static Boolean IsNull(this string str)
    {
        return string.IsNullOrEmpty(str);
    }

这将不起作用,因为Queryable.Contains需要类型t作为参数,而不是字符串。这就是为什么我需要执行Queryable.Wherep=>p.EdsColumn。Containssearchthis@Ed.S.:将T更改为字符串。那更好吗?我想应该有两具尸体。一个用于字符串.Contains,另一个用于Where。var stringBody=Expression.Call typeofstring,Contains,新类型[]{typeofstring},Expression.Propertyarg,columnName,Expression.Constantkeyword;var whereBody=Expression.Call typeofQueryable,Where,new Type[]{typeofQueryable},-这就是我丢失的地方。@Ed.S.:whereBody正是返回源的内容。Wherepredicate;在我的代码中返回。它首先生成谓词p=>p.ColumnName.Containskeyword,然后返回source.Wherepredicate.@dtb:类型“System.String”上仍然不存在“Contains”方法。有什么想法吗?在正文中,我将这两种类型的更改为字符串,因为Queryable.containstthis IQueryable,。。。不起作用这不起作用,因为Queryable.Contains希望t类型作为参数,而不是字符串。这就是为什么我需要执行Queryable.Wherep=>p.EdsColumn。Containssearchthis@Ed.S.:将T更改为字符串。那更好吗?我想应该有两具尸体。一个用于字符串.Contains,另一个用于Where。var stringBody=Expression.Call typeofstring,Contains,新类型[]{typeofstring},Expression.Propertyarg,columnName,Expression.Constantkeyword;var whereBody=Expression.callTypeOfQueryAB
le,Where,new Type[]{typeofQueryable},-这就是我丢失的地方。@Ed.S:您的whereBody正是返回源的内容。Wherepredicate;在我的代码中返回。它首先生成谓词p=>p.ColumnName.Containskeyword,然后返回source.Wherepredicate.@dtb:类型“System.String”上仍然不存在“Contains”方法。有什么想法吗?在正文中,我将这两种类型的更改为字符串,因为Queryable.containstthis IQueryable,。。。不会工作谢谢,我已将您的建议纳入我正在进行的工作中。谢谢,我已将您的建议纳入我正在进行的工作中。您解决过LINQ到实体中不受支持的问题吗?您解决过LINQ到实体中不受支持的问题吗?