получить выражение метода в дереве выражений - PullRequest
2 голосов
/ 23 августа 2009

Я хочу создать следующий запрос в деревьях выражений:

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

Как мне создать выражение:

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

Я попробовал все, даже застрял при получении MethodInfo поля для метода Expression.Call. Поле - это метод расширения DataRowExtentions.

Должен ли я использовать Expression.Call () для этого? Как я могу получить MethodInfo? Есть ли более простой способ сделать это?

я пытался:

ParameterExpression dataRow = Expression.Parameter (typeof (DataRowExtensions), "dataRow"); Выражение влево = Expression.Call (dataRow, typeof (DataRowExtensions) .GetMethod ("Field"));

но это не работает.


Я хочу создать динамические фильтры для данных внутри IQueryable tempResults.

Пользователь установит флажки в графическом интерфейсе, которые будут добавлять выражения «Где» к данным в tempResults. когда пользователь выбирает «Столбец», я хочу представить DataRows, где ColumnName = «Столбец».

именно поэтому мне нужно создать выражение where. но я так застрял на методе. Я тоже это попробовал:

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

но это тоже не работает.

Есть ли другие способы сделать это?

1 Ответ

2 голосов
/ 23 августа 2009

Замена ответа после уточнения в комментариях:

Для последовательного создания дополнительных фильтров вам не нужны деревья выражений; Вы можете звонить .Where несколько раз (при необходимости, один раз для каждого поискового запроса) - например:

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

Единственное, что нужно посмотреть, это проблема «захвата»; не используйте повторно ни один из value1, value2 и т. д., иначе последнее значение будет применяться к более ранним фильтрам ...


Для примера комбинации делегатов (из комментариев) - обратите внимание, что здесь я упустил аспект DataTable исключительно для того, чтобы сделать пример короче (он будет работать идентично):

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

(оригинальный ответ)

На самом деле, этот вариант LINQ не будет использовать дерево выражений ... он будет использовать делегат; но вы можете построить дерево и скомпилировать его, если вы действительно хотите ... Я не уверен, почему вы это сделаете. Что ты хочешь делать? Я приведу пример ...


Вот, пожалуйста; здесь используется дерево выражений, но я не могу придумать ни одной веской причины для этого, кроме как доказать, что вы можете!

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

    }
}
...