使用参数的索引器构建表达式树 [英] Building Expression Tree Using a Parameter's Indexer

查看:190
本文介绍了使用参数的索引器构建表达式树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个属性为Dictionary的类

Given a class that has a property that is a Dictionary

public class Product
{
    public Dictionary<string, string> Attributes { get { return attributes; } }

    private Dictionary<string, string> attributes = new Dictionary<string, string>();
}

我希望能够根据标准匹配产品列表中的产品从数据存储中检索的格式为

I want to be able to match products in a list of products based on criteria that are retrieved from a data store that are in the format of

Brand == Tyco
Color != Blue

我目前的方法是从过滤器构造一个表达式,然后将该表达式作为参数传递给LINQ 其中方法调用如下

My current approach is to construct an expression from the filter, and then pass that expression as the parameter to a LINQ Where method call like so

products = products.Where(myConstructedExpression);

其中 myConstructedExpression 通常是一个lamda表达式看起来像

where myConstructedExpression would normally be a lamda expression that looks like

p => p.Attributes[attribute] == value

我已经汇编了以下代码进行测试,但是始终不会调用 lambda.Compile(),无论我为他离开表达式而尝试。

I have assembled the following code for testing purposes, but it always fails the call to lambda.Compile() regardless of what I have tried for he left expression.

Dictionary<string, ExpressionType> expressionType = new Dictionary<string, ExpressionType>();
expressionType.Add("==", ExpressionType.Equal);
expressionType.Add("!=", ExpressionType.NotEqual);

string filter = "Brand == Tyco";
string[] fields = filter.Split(' ');
string attribute = fields[0];
string op = fields[1];
string value = fields[2];

Product product = new Product();
product.Attributes.Add("Brand", "Tyco"); 

var parameter = Expression.Parameter(typeof(Product), "p");
var left = /***** THIS IS WHAT I AM FAILING TO CONSTRUCT PROPERLY ********/
var right = Expression.Constant(value);
var operation = Expression.MakeBinary(expressionType[op], left, right);
var lambda = Expression.Lambda<Func<Product, bool>>(operation, parameter);

var result = lambda.Compile()(product);

问题


  1. 这是一个合理的方法,如果是这样,

  2. 如何构造左表达式?


推荐答案

所以要获得 p => p.Attributes [Brand]< someoperator> Tyco,你可以这样做。

So to get p => p.Attributes["Brand"] <someoperator> "Tyco", you can do this.

使用索引类型的窍门是使用他们的 Item 属性(您也可以使用 get_item 方法)

The "trick", to work with indexed types, is to use their Item property (you could also work with the get_item method)

var parameter = Expression.Parameter(typeof(Product), "p");
Expression left = Expression.Property(parameter, "Attributes");
left = Expression.Property(left, "Item", new Expression[] { Expression.Constant(attribute) });

编辑

具有 IDictionary.ContainsKey(< value>) test

的版本真的是一步一步,但是我认为这使得事情更清楚起初。

really step by step, but I think this makes things clearer at first.

//left part of lambda, p
var parameter = Expression.Parameter(typeof(Product), "p");
//right part
//p.Attributes
Expression left = Expression.Property(parameter, "Attributes");

var method = typeof(IDictionary<string, string>).GetMethod("ContainsKey");
//p.Attributes.ContainsKey("Brand");
Expression containsExpression = Expression.Call(left, method, Expression.Constant(attribute));
//p.Attributes.Item["Brand"]
Expression keyExpression= Expression.Property(left, "Item", new Expression[] { Expression.Constant(attribute) });
//"Tyco"
var right = Expression.Constant(value);
//{p => IIF(p.Attributes.ContainsKey("Brand"), (p.Attributes.Item["Brand"] == "Tyco"), False)}
Expression operation = Expression.Condition(
                           containsExpression,
                           Expression.MakeBinary(expressionType[op], keyExpression, right), 
                           Expression.Constant(false));
var lambda = Expression.Lambda<Func<Product, bool>>(operation, parameter);

这篇关于使用参数的索引器构建表达式树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆