2017-02-22 312 views
1

我有这个类:如何从lambda表达式中获取值?

public class CustomerFilter 
{ 
    public int Id { get; set; } 
    public int Name { get; set; } 
} 

而且它使用的是这样的:

public class Search 
{ 
    private Expression<Func<CustomerFilter, bool>> customerfilter; 

    public Expression<Func<CustomerFilter, bool>> CustomerFilter 
    { 
     set { customerfilter = value; } 
    } 
} 

var search = new Search(); 
search.CustomerFilter = (x => x.Id == 1); 

从搜索类中,我怎样才能得到一个属性,而无需使用ExpressionVisitor价值?例如:

var customerId = customerFilter.Id; //Or something similar 

回答

2

不太明白为什么你需要它。但是,你可以做这样的事情:

public class Search 
{ 
    private Expression<Func<CustomerFilter, bool>> customerfilter; 

    public Expression<Func<CustomerFilter, bool>> CustomerFilter 
    { 
     set { customerfilter = value; } 
    } 

    public object GetValue(CustomerFilter filter) 
    { 
     var property = (customerfilter.Body as BinaryExpression).Left; 
     var lambda =Expression.Lambda(property, customerfilter.Parameters.First()); 
     return lambda.Compile().DynamicInvoke(filter); 
    } 
} 

有了这样的用法:

var search = new Search(); 
search.CustomerFilter = (x => x.Id == 1); 
var filter = new CustomerFilter {Id = 12}; 
search.GetValue(filter).Dump(); 

我得到12作为输出

+0

你从'CustomerFilter的新实例所获得的价值'。我需要从表达式本身获得价值。 –

+0

表达式没有任何实例,您可以构建一个获取值的新表达式,但您需要一个实例来应用 –

2

如果您CustomerFilter仅支持MemberExpression==ConstantExpression就像在你的示例代码。然后,您可以直接从Expression对象获取信息。

var propertyName = ((MemberExpression)((BinaryExpression)customerfilter.Body).Left).Member.Name; 
var propertyValue = ((ConstantExpression)((BinaryExpression)customerfilter.Body).Right).Value; 

如果你想支持更复杂的表达式,ExpressionVisitor应该使用解析expression树。

+0

,该表达式提供了正确的值。在答案的样本中,它是1.我不认为这是OP想要的。否则他想要什么,如果我理解正确的话是不可能的。 –

+0

请记住,这会对可能的lambda表达式产生限制,这可能很容易被他人忽视(或者在一段时间后)。您可能需要在'CustomerFilter'的setter中添加一个检查来确保给定的表达式处于受支持的形式。 – wkl

0

这是有点误导你有一个类和属性CustomerFilter代表非常不同的事情。据我了解,这个类将更好地被命名为Customer

public class Customer 
{ 
    public int Id { get; set; } 
    public int Name { get; set; } 
} 

public class Search 
{ 
    private Expression<Func<Customer, bool>> customerfilter; 

    public Expression<Func<Customer, bool>> CustomerFilter 
    { 
     set { customerfilter = value; } 
    } 
} 

var search = new Search(); 
search.CustomerFilter = (x => x.Id == 1); 

然后更明显的是,有一个在您Search类没有财产customerFilter.Id。你只有一个表达式,可以采取任何(!)Customer并将其转换为bool。它通过将Customer.Id与给定值进行比较来实现,但Search不知道这一点。

如果你需要得到比较ID在Search,我建议你改变CustomerFilter属性的类型具有公共ComparisonId财产,并基于该ID的过滤表达式类:

class CustomerIdFilter // note: this will not replace your existing CustomerFilter which I have renamed to Customer 
{ 
    public CustomerIdFilter(int id){ ComparisonId = id; } 
    public int ComparisonId{ get; private set} 
    // To filter use this 
    public bool IsValid(Customer c){ return c.Id == ComparisonId; } 
    // or maybe something similar to this, if necessary 
    public Expression<Func<Customer, bool>>FilterExpression 
    { 
     get 
     { 
      return (x=>x.Id == ComparisonId); 
     } 
    } 
} 

你的代码会改成s.th.这样便:

public class Search 
{ 
    private CustomerIdFilter customerfilter; 

    public CustomerIdFilter CustomerFilter 
    { 
     set { customerfilter = value; } 
    } 
} 

var search = new Search(); 
search.CustomerFilter = new CustomerIdFilter(1); 
0

再进一步根据xwlantian的答案,我做了以下和它的工作原理简单表达式:

var value = Expression.Lambda(((BinaryExpression)customerFilter.Body).Right).Compile().DynamicInvoke();