关于c#:获取Expression树中方法的表达式

get expression of method in Expression tree

我想在表达式树中创建以下查询:

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

如何创建表达式:

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

我什么都试过了,我甚至一直在为expression.call方法获取字段的MethodInfo。字段是DataRowExtensions的扩展方法。

我必须为此使用expression.call()吗?我怎样才能得到卫理公会信息?有没有更简单的方法?

我试过:

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

但它不起作用。

我想在iqueryable tempresults内的数据上创建动态过滤器。

用户将选中GUI上的复选框,该复选框将向tempresults中的数据添加"where"表达式。当用户选择"column"时,我想显示columnname="column"所在的数据行。

这就是为什么我需要创建Where表达式。但我对卫理公会的事很感兴趣。我也试过这个:

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

但它也不管用。

还有其他方法吗?


在评论中澄清后的替换回答:

为了连续地构建额外的过滤器,您不需要表达式树;您可以多次调用.Where(根据需要,每个搜索词调用一次)-例如:

1
2
3
4
5
6
7
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);
}

唯一要注意的是"捕获"问题;确保不要重复使用任何value1value2等-否则最后一个值将应用于早期的过滤器…

对于委托组合的示例(来自注释)-请注意,我在这里删除了DataTable方面,只是为了缩短示例的长度(它的工作方式相同):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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的变体不会使用表达式树…它将使用委托;但是如果您真的想要,您可以构建树并编译它…不过,我不知道你为什么要这样做。你想做什么?我来举个例子…

给你,这使用了表达式树,但是我想不出一个好的理由来做这个,除了证明你可以!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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());

    }
}