получить выражение метода в дереве выражений

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

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»); Выражение left = Expression.Call (dataRow, typeof (DataRowExtensions) .GetMethod ("Поле"));

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


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

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

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

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

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

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


person Rodniko    schedule 23.08.2009    source источник


Ответы (1)


Ответ на замену после разъяснения в комментариях:

Для последовательного построения дополнительных фильтров вам не нужны деревья выражений; вы можете вызывать .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());

    }
}
person Marc Gravell    schedule 23.08.2009
comment
я хочу создать динамические фильтры для данных внутри IQueryable ‹DataRow› tempResults. Пользователь будет отмечать флажки в графическом интерфейсе, которые будут добавлять выражения «Где» к данным в tempResults. когда пользователь выбирает столбец, я хочу представить DataRows, где ColumnName = Column. вот почему мне нужно создать выражение where. но я так зациклился на вещи MethodInfo .... Я тоже пробовал это: MethodInfo FieldStringMethodInfo = typeof (DataRowExtensions) .GetMethod (Field ‹string›, BindingFlags.Public | BindingFlags.Static); это тоже не работает. Есть другие способы сделать это? - person Rodniko; 23.08.2009
comment
Ах! Для этого вам не нужны деревья выражений ... см. Обновление (вверху) - person Marc Gravell; 23.08.2009
comment
Спасибо, Марк, пример Asenumerable () хорош, но мне нужен способ его динамического создания, потому что пользователь может выбрать: row = ›row.Field ‹string› (Col1) == value1 || row.Field ‹string› (Col1) == value2 и в следующий раз: row = ›row.Field ‹string› (Col1) == value1 || row.Field ‹string› (Col1) == value2 || row.Field ‹string› (Col1) == value3, поэтому мне нужно составлять его динамически, мне нужно найти способ добавить любые фильтры, которые я хочу, в предложение where и только затем выполнить запрос. Могу ли я сделать это более простым способом, чем пример дерева выражений? - person Rodniko; 23.08.2009
comment
Вы можете привести пример того, что вы имеете в виду? - person Marc Gravell; 23.08.2009
comment
пользователь выбирает между 3 видами шариков (например). он может выбрать синий цвет и нажать кнопку «Отправить». в этом случае я создаю запрос с предложением where следующим образом: where baloon == blue. в следующий раз он проверяет красный, желтый и серый и нажимает кнопку подтверждения. в этом случае мне нужно составить запрос с классом where следующим образом: where baloon == red или baloon == yellow or baloon == grey. вот почему я не могу этого сделать: query.Where (row = ›row.Field ‹string› (baloon) == красный); потому что в некоторых случаях этого недостаточно. мне нужно использовать для этого динамические лямбда-выражения? - person Rodniko; 24.08.2009
comment
Ну, лично я бы использовал Список цветов и использовал Contains, т.е. Where(row => colors.Contains(row.Field<SomeType>("Color"))). Полный Expression подход является лишь необходимым усложнением в случае серверной части на основе синтаксического анализатора (LINQ-to-SQL, EF и т. Д.); в этом случае (LINQ-to-Objects) я бы с радостью использовал комбинацию делегатов; Попробую обновить ... - person Marc Gravell; 24.08.2009
comment
МОЙ БОГ!! может ли это быть так просто ??? используя список? Работает как часы! и это именно то решение, которое я искал - способ динамического создания моего собственного лямбда-выражения с предложением Where, которое указывает: включать только строку, которая имеет одно из следующих значений для определенного столбца. Большое спасибо за ваше время, Марк. - person Rodniko; 25.08.2009
comment
@Rodniko - Contains было бы проще ... это было для обсуждения конкретного случая, но если вы счастливы ... - person Marc Gravell; 25.08.2009