매개 변수의 인덱서를 사용하여 표현식 트리 만들기

c# expression expression-trees lambda linq

문제

사전 인 속성을 가진 클래스가 주어진다.

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

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

다음과 같은 형식의 데이터 저장소에서 검색된 기준에 따라 제품 목록의 제품을 검색 할 수 있기를 원합니다.

Brand == Tyco
Color != Blue

내 현재 접근 방식은 필터에서 표현식을 구성한 다음 해당 식을 LINQ에 매개 변수로 전달하는 것입니다. Where 메서드 호출

products = products.Where(myConstructedExpression);

여기서 myConstructedExpression 은 일반적으로 다음과 같은 lamda 표현식입니다.

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

테스트 목적으로 다음 코드를 어셈블했지만 항상 표현을 lambda.Compile() 했던 것에 상관없이 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);

질문들

  1. 이것도 합리적인 접근 방법이며, 그렇다면,
  2. 왼쪽 표현식은 어떻게 구성합니까?

수락 된 답변

따라서 p => p.Attributes["Brand"] <someoperator> "Tyco" 를 얻으려면이 작업을 수행 할 수 있습니다.

인덱싱 된 유형에 대해 작업하는 "트릭"은 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) });

편집하다

IDictionary.ContainsKey(<value>) 테스트 버전

정말 단계적으로 단계적으로,하지만 이것은 처음에 물건을 명확하게 생각합니다.

//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 with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.