Dynamic LINQ - Is There A .NET 4 Version?

2019-01-21 11:06发布

I'm looking to use LINQ for some searching routines and wanted to have some dynamic where clauses. So, for example, if a user wants to search by city or search by state, I would have a dynamic LINQ Where<> call instead of creating two strongly typed LINQ expressions and then using the appropriate one based on how the user wants to search.

So I would like to do this:

String criteria="p.City='Pittsburgh'";  //or "p.State='PA'"
personData.Where(criteria)

instead of

personData.Where(p => p.City=="Pittsburgh");

or

personData.Where(p => p.State=="PA");

I came across a blog post by Scott Guthrie talking about Dynamic LINQ in the Visual Studio 2008 samples. This seems to do what I want, but my questions are:

  1. Is this sample library supported by Microsoft?
  2. Scott Guthrie's article is in regards to VS2008 (.NET 3.5). Is there a better option for .NET 4? Maybe something that was released with .NET 4 that accomplishes the same thing (or something very close)?

Thanks in advance!

4条回答
Luminary・发光体
2楼-- · 2019-01-21 11:23

You may want to take a look at PredicateBuilder

查看更多
不美不萌又怎样
3楼-- · 2019-01-21 11:23

It should now be available. I could download it through NuGet: http://www.nuget.org/packages/System.Linq.Dynamic/

查看更多
家丑人穷心不美
4楼-- · 2019-01-21 11:26

I don't think it's "supported" by Microsoft - it seems to be released under a public license, which says in part:

(E) The software is licensed “as-is.” You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

On your second question, I don't think there's a .NET 4 version. The 3.5 should work fine in a 4.0 project, and I don't think there's really much to add in. As I understand it, this was a nifty little library for doing those occasional, one-off string-based linq queries. Maybe you were for some reason manually sorting a grid, and needed to modify your collections sort order based on a string representing the property in question. Voila. I doubt you'll see a lot of effort put into adding a lot of features into this.

查看更多
ら.Afraid
5楼-- · 2019-01-21 11:40

This feature would be really nice to have. A similar feature exists in ADO.net Datatables. It would be really helpful for LinqToSql as well. Sure you would lose strongly typed checking, but thats the whole point, you want dynamic searches. If you handle the exceptions properly I really think its a feature worth having.

You might consider adding a feature request to Microsoft Connect. The library already exists maybe they will consider adding official support for it. If you do make a feature request make sure you post a link here so we can vote for it. Microsoft Connect has voting system similar to stackoverflow. I have submitted a few myself LinqtoSql TableUpdate and VB.net Readonly Interfaces like C#.

I remember having some trouble with this library. I think it had something to do with static methods.

I found it better to develop the expressions I needed. This article by Ilya Builuk demonstrates custom expressions. The nice thing about Ilya's framework it removes a lot of the boilerplate code when doing operations like sorting for jqGrid.

I found it extremely helpful when learning about the underlying concepts of expressions.

The nice thing about this code is that it allows you to use dot operators for getters. Person.Age or if you want to violate Demeter you can even do multiple getters.

The code can be improved upon. I believe I added StartsWith and only allowed it for string operations as well as a few other search operations. Regardless its worth a look, it helped me understand linq expressions a lot.

public static IQueryable<T> Where<T>(this IQueryable<T> query, string column, object value, WhereOperation operation)
{
    if (string.IsNullOrEmpty(column))
        return query;

    ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");

    MemberExpression memberAccess = null;
    foreach (var property in column.Split('.'))
        memberAccess = MemberExpression.Property
           (memberAccess ?? (parameter as Expression), property);

    //change param value type
    //necessary to getting bool from string
    ConstantExpression filter = Expression.Constant
        (
            Convert.ChangeType(value, memberAccess.Type)
        );

    //switch operation
    Expression condition = null;
    LambdaExpression lambda = null;
    switch (operation)
    {
        //equal ==
        case WhereOperation.Equal:
            condition = Expression.Equal(memberAccess, filter);
            lambda = Expression.Lambda(condition, parameter);
            break;
        //not equal !=
        case WhereOperation.NotEqual:
            condition = Expression.NotEqual(memberAccess, filter);
            lambda = Expression.Lambda(condition, parameter);
            break;
        //string.Contains()
        case WhereOperation.Contains:
            condition = Expression.Call(memberAccess,
                typeof(string).GetMethod("Contains"),
                Expression.Constant(value));
            lambda = Expression.Lambda(condition, parameter);
            break;
    }


    MethodCallExpression result = Expression.Call(
           typeof(Queryable), "Where",
           new[] { query.ElementType },
           query.Expression,
           lambda);

    return query.Provider.CreateQuery<T>(result);
}

WhereOperation enumerator:

public enum WhereOperation { Equal, NotEqual, Contains }
查看更多
登录 后发表回答