【问题标题】:get expression of method in Expression tree获取表达式树中方法的表达式
【发布时间】:2009-08-23 12:43:18
【问题描述】:

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

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

如何创建表达式:

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

我尝试了所有方法,我什至在为 Expression.Call 方法获取 Field 的 MethodInfo 时遇到了困难。 Field 是 DataRowExtentions 的一个扩展方法。

我必须为此使用 Expression.Call() 吗? 我如何获得 MethodInfo? 有没有更简单的方法?

我试过了:

ParameterExpression dataRow = Expression.Parameter(typeof(DataRowExtensions), "dataRow"); 左表达式 = Expression.Call(dataRow, typeof(DataRowExtensions).GetMethod("Field"));

但它不起作用。


我想对 IQueryable tempResults 中的数据创建动态过滤器。

用户将选中 GUI 上的复选框,该复选框将向 tempResults 中的数据添加“Where”表达式。当用户选择“Column”时,我想显示 ColumnName = “Column”的 DataRows。

这就是为什么我需要创建 where 表达式。但我非常坚持 MethodInfo 的事情。我也试过这个:

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

但它也不起作用。

还有其他方法吗?

【问题讨论】:

    标签: c# expression-trees methodinfo


    【解决方案1】:

    在 cmets 中澄清后替换答案:

    为了连续构建额外的过滤器,您不需要表达式树;您可以多次致电.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);
    }
    

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


    对于委托组合的示例(来自 cmets) - 请注意,我在这里删除了 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());
    
        }
    }
    

    【讨论】:

    • 我想对 IQueryable tempResults 中的数据创建动态过滤器。用户将选中 GUI 上的复选框,这些复选框将向 tempResults 中的数据添加“Where”表达式。当用户选择“列”时,我想显示 ColumnName =“列”的 DataRows。这就是为什么我需要创建 where 表达式。但我非常坚持 MethodInfo 的事情......我也试过这个: MethodInfo FieldStringMethodInfo = typeof(DataRowExtensions).GetMethod("Field", BindingFlags.Public | BindingFlags.Static);它也不起作用。还有其他方法吗?
    • 谢谢 marc,Asenumerable() 示例很好,但我需要一种动态创建它的方法,因为用户可以选择:row => row.Field("Col1") = = 值1 || row.Field("Col1") == value2 下一次:row => row.Field("Col1") == value1 || row.Field("Col1") == value2 || row.Field("Col1") == value3 这就是我需要动态组合它的原因,我需要找到一种方法来“将我想要的任何过滤器添加到 where 子句”,然后才执行查询。我可以以比表达式树示例更简单的方式做到这一点吗?
    • 你能举例说明你的意思吗?
    • 用户在 3 种气球中进行选择(例如)。他可以选择蓝色并按下“提交”按钮。在这种情况下,我使用这样的 where 子句创建一个查询:where baloon == "blue"。下次他检查红色、黄色和灰色并按下提交按钮。在这种情况下,我需要使用这样的 where 类来编写查询:其中 baloon ==“red”或 baloon ==“yellow”或 baloon ==“gray”。这就是为什么我不能这样做: query.Where(row => row.Field("baloon") == "red");因为在某些情况下这还不够。我需要使用动态 lambda 表达式来做到这一点吗?
    • 嗯,个人我会使用颜色列表并使用包含,即Where(row =&gt; colors.Contains(row.Field&lt;SomeType&gt;("Color")))。在基于解析器的后端(LINQ-to-SQL、EF 等)的情况下,完整的Expression 方法只是必要的复杂性;对于这种情况(LINQ-to-Objects),我很乐意使用委托组合;我会尝试更新...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多