[英]Building Expression Tree Using a Parameter's Indexer
Given a class that has a property that is a Dictionary 给定一个类,该类的属性为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
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 我当前的方法是从过滤器构造一个表达式,然后将该表达式作为参数传递给LINQ
Where
方法调用,如下所示
products = products.Where(myConstructedExpression);
where myConstructedExpression
would normally be a lamda expression that looks like 其中
myConstructedExpression
通常是一个lamda表达式,看起来像
p => p.Attributes[attribute] == value
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. 我已经为测试目的汇编了以下代码,但是无论我为他留下的表达式尝试了什么,它始终无法调用
lambda.Compile()
。
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);
Questions 问题
So to get p => p.Attributes["Brand"] <someoperator> "Tyco"
, you can do this. 因此,要获得
p => p.Attributes["Brand"] <someoperator> "Tyco"
,您可以执行此操作。
The "trick", to work with indexed types, is to use their Item property (you could also work with the get_item
method) 使用索引类型的“技巧”是使用其Item属性(您也可以使用
get_item
方法)
var parameter = Expression.Parameter(typeof(Product), "p");
Expression left = Expression.Property(parameter, "Attributes");
left = Expression.Property(left, "Item", new Expression[] { Expression.Constant(attribute) });
EDIT 编辑
the version with the IDictionary.ContainsKey(<value>)
test 使用
IDictionary.ContainsKey(<value>)
测试的版本
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.