获取表达式树中方法的表达式

发布于 2024-08-02 20:37:30 字数 1092 浏览 3 评论 0原文

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

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() 吗? 我如何获取方法信息? 有更简单的方法吗?

我试过 :

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

但它不起作用。


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

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

这就是为什么我需要创建 where 表达式。但我对 MethodInfo 的事情很困惑。我也尝试过这个:

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

但它也不起作用。

还有其他方法吗?

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

守不住的情 2024-08-09 20:37:30

注释中澄清后的替换答案:

对于连续构建附加过滤器,您不需要表达式树;您可以多次调用 .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 等 - 否则最后一个值将应用于早期过滤器


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

    }
}

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

    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文