Question

i want to create the following query in expression trees:

var test = from datarow in tempResults
           where datarow.Field<String>("ColumnName") == "Column"
           select datarow;

How do i create the expression:

datarow.Field<String>("ColumnName")?

i tried everything, i even got stuck on getting the MethodInfo of Field for the Expression.Call method. Field is an extention Method of DataRowExtentions.

Do i have to use Expression.Call() for this? How do i get the MethodInfo? is there a simplier way to do it ?

i tried :

ParameterExpression dataRow = Expression.Parameter(typeof(DataRowExtensions), "dataRow"); Expression left = Expression.Call(dataRow, typeof(DataRowExtensions).GetMethod("Field"));

but it doesn't work.


i want to create dynamic filters on the data inside IQueryable tempResults.

The user will check on checkboxes on the GUI that will add 'Where' expressions to the data in tempResults. when the user chooses "Column" i want to present the DataRows where ColumnName = "Column".

that is why i need to create the where expression. but i'm so stuck on the MethodInfo thing. I tried this too:

MethodInfo FieldStringMethodInfo = typeof(DataRowExtensions).GetMethod("Field", BindingFlags.Public | BindingFlags.Static);

but it doesn't work too.

Is there other ways to do it ?

Was it helpful?

Solution

Replacement answer following clarification in comments:

For successively building additional filters, you don't need expression trees; you can call .Where multiple times (as necessary, once per search term) - for example:

IEnumerable<DataRow> query = tempResults.AsEnumerable();
if(!string.IsNullOrEmpty(value1)) {
    query = query.Where(row => row.Field<string>("Col1") == value1);
}
if (!string.IsNullOrEmpty(value2)) {
    query = query.Where(row => row.Field<string>("Col2") == value2);
}

The only thing to watch is the "capture" issue; be sure not to re-use any of the value1, value2 etc - otherwise the last value will apply to earlier filters...


For an example of delegate combination (from comments) - note that I've dropped the DataTable aspect here purely to make the example shorter (it will work identically):

public static class Predicate {
    public static Func<T, bool> OrElse<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) || rhs(obj);
    }
    public static Func<T, bool> AndAlso<T>(
            this Func<T, bool> lhs, Func<T, bool> rhs) {
        return lhs == null ? rhs : obj => lhs(obj) && rhs(obj);
    }
}
class Data {
    public string Color { get; set; }
}
class Program {
    static void Main() {
        bool redChecked = true, greenChecked = true; // from UI...
        List<Data> list = new List<Data>() {
            new Data { Color = "red"},
            new Data { Color = "blue"},
            new Data { Color = "green"},
        };
        Func<Data, bool> filter = null;
        if (redChecked) {
            filter = filter.OrElse(row => row.Color == "red");
        }
        if (greenChecked) {
            filter = filter.OrElse(row => row.Color == "green");
        }
        if (filter == null) filter = x => true; // wildcard

        var qry = list.Where(filter);

        foreach (var row in qry) {
            Console.WriteLine(row.Color);
        }
    }
}

(original answer)

Actually, that variant of LINQ won't use an expression tree... it will use a delegate; but you can build the tree and compile it if you really want... I'm not sure why you would, though. What do you want to do? I'll knock up an example...


Here you go; this uses an expression tree, but I can't think of a single good reason to do this, other than to prove that you can!

public static class MyExtensions
{
    public static IQueryable<TRow> Where<TRow, TValue>(
        this IQueryable<TRow> rows,
        string columnName, TValue value)
        where TRow : DataRow
    {
        var param = Expression.Parameter(typeof(TRow), "row");
        var fieldMethod = (from method in typeof(DataRowExtensions).GetMethods()
                           where method.Name == "Field"
                           && method.IsGenericMethod
                           let args = method.GetParameters()
                           where args.Length == 2
                           && args[1].ParameterType == typeof(string)
                           select method)
                           .Single()
                           .MakeGenericMethod(typeof(TValue));
        var body = Expression.Equal(
            Expression.Call(null,fieldMethod,
                param,
                Expression.Constant(columnName, typeof(string))),
            Expression.Constant(value, typeof(TValue))
        );
        var lambda = Expression.Lambda<Func<TRow, bool>>(body, param);
        return rows.Where(lambda);

    }
}
class Program
{
    static void Main(string[] args)
    {
        DataTable tempResults = new DataTable();
        tempResults.Columns.Add("ColumnName");
        tempResults.Rows.Add("foo");
        tempResults.Rows.Add("Column");

        var test = tempResults.AsEnumerable().AsQueryable()
                   .Where("ColumnName", "Column");
        Console.WriteLine(test.Count());

    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top