Converting Where from LINQ Clause to Dynamic LINQ

I want to go from

        var selectData = (from i in data
                          where i.Name == "Bob1"
                          select i);

      

For

        var selectData = (from i in data
                          select i).Where("Name==Bob1");

      

I've tried various approaches ( AsQueryable

, Where<SomeData>

) but can't get the second form to compile.

I am not very good at general C # extension methods. <Tsource>

doesn't make sense to me, so this might be a problem. Also, I don't understand why I can print .Where()

when intellisense only displays .Where<>

(general). I expect to see the second one Where

without a common symbol ... alas, I don't.

Class

public class SomeData
{
    public string Name { get; set; }
    public string Address { get; set; }
}

      

UPDATE
There seems to be some confusion as to how Where () can be used, which could very well be my mistake. See related question. Based on this answer, the property name in the where clause is perfectly legal. I need the property to remain a string. If that means dynamic LINQ is required, then let it be ... what I need.

+3


source to share


5 answers


With all your help, I was able to get the conversion to function.



  • Install dynamic LINQ (I used NUGET. Internet search for System.Linq.Dynamic)
  • Add to using System.Linq.Dynamic

  • The request should be of the form

        var selectData = (from i in data
                          select i).AsQueryable().Where("Name = @0","Bob1");//@0 is called an identifier.  "Name = Bob1" straight up fails.
    
          

  • Install ScottGU C # Sample Library ... it helps. ( VB ) ( Original post )

+2


source


var selectData = (from i in data
                  select i).Where(datum => datum.Name == "Bob1");

      

The method Where

accepts a delegate, not a string, so you need to pass a delegate or lambda.



Edit: Based on your comment on one of the other answers, you would need to use Reflection in order to dynamically change the property value dynamically.

Edit: It looks like you need to download the source code for the Dynamic Linq library separately.

+2


source


UPDATE

I misunderstood the question; the solution to the problem is to download Dynamic Linq and reference it. I'll leave my answer below, which addresses the side questions you asked regarding common extension methods.


var selectData = (from i in data 
    select i).Where(d => d.Name=="Bob1");

      

But why not this:

var selectData = data.Where(d => d.Name=="Bob1");

      

Regarding the "non-tribal" version where there is no such thing. In the above calls, the type parameter of the generic method is implicit; it was output by the compiler, which compiles the call exactly the same way it would compile this:

var selectData = data.Where<SomeData>(d => d.Name=="Bob1");

      

Perhaps implementing a method sketch Where

will help reduce your confusion about the parameter TSource

:

public static IEnumerable<TSource> Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach (TSource item in source)
        if (predicate(item))
            yield return item;
}

      

TSource

is the element type of the sequence you are requesting. It is also the element type of the result sequence.

The compiler needs to know the type for at least two reasons:

First, we need to call a function on each item to determine whether to include it in the result sequence. The compiler needs to know that the parameter referent predicate

can safely accept a parameter of type TSource.

The second reason in this case is somewhat trivial; item

must be an assignment that is compatible with TSource

because it is used in a statement yield return

. Of course it is compatible because it is of the same type.

+1


source


I believe this is what you are looking for:

http://www.albahari.com/nutshell/predicatebuilder.aspx

Example

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}

      

Source

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

public static class PredicateBuilder
{
  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  public static Expression<Func<T, bool>> False<T> () { return f => false; }

  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  }

  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  }
}

      

0


source


Here's some simple code using an expression tree to do what you want. This will only work for properties == ...... requests of that particular type. You can of course change this and make it generic as you like.

    public void Test()
    {
        List<SomeData> data = new List<SomeData>();
        data.Add(new SomeData("Mark", "Ledgewood Drive"));
        data.Add(new SomeData("Tim", "Sumpter Drive"));
        data.Add(new SomeData("Sean", "Leroy Drive"));
        data.Add(new SomeData("Bob", "Wilmington Road"));
        data.Add(new SomeData("Sean", "Sunset Blvd"));

        List<SomeData> result = data.Where(BuildExpression("Name", "Mark")).ToList();
        List<SomeData> result2 = data.Where(BuildExpression("Address", "Wilmington Road")).ToList();
    }

    private Func<SomeData, bool> BuildExpression(string propertyName, string value)
    {
        ParameterExpression pe = Expression.Parameter(typeof(SomeData), "someData");
        Expression left = Expression.Property(pe, propertyName);
        Expression right = Expression.Constant(value);
        BinaryExpression binary = Expression.Equal(left, right);
        Expression<Func<SomeData, bool>> lambda = Expression.Lambda<Func<SomeData, bool>>(binary, pe);
        return lambda.Compile();
    }

      

0


source







All Articles