【问题标题】:Expression.PropertyOrField returns "not a member of type 'System.String'" for string propertyExpression.PropertyOrField 为字符串属性返回“不是‘System.String’类型的成员”
【发布时间】:2016-03-25 14:49:06
【问题描述】:

我正在尝试为规则引擎动态构建表达式,在我尝试允许将嵌套类型和属性指定为操作数之前,一切进展顺利。示例:

ExpressionBuilder

public Expression BuildExpression<T>(string propertyName, Enums.Operator ruleOperator, object value, ParameterExpression parameterExpression)
    {
        ExpressionType expressionType = new ExpressionType();
        Expression body = parameterExpression;

        foreach (var member in propertyName.Split('.'))
        {
            body = MemberExpression.Property(body, member);
        }

        var leftOperand = MemberExpression.PropertyOrField(body, propertyName);
        var rightOperand = Expression.Constant(Convert.ChangeType(value, value.GetType()));
        FieldInfo fieldInfo = expressionType.GetType().GetField(Enum.GetName(typeof(Enums.Operator), ruleOperator));
        var expressionTypeValue = (ExpressionType)fieldInfo.GetValue(ruleOperator);

        return CastBuildExpression(expressionTypeValue, value, leftOperand, rightOperand);
    }

规则引擎

public Func<T, bool>[] CombineRules<T>(Criterion[] criteria)
    {
        List<Func<T, bool>> list = new List<Func<T, bool>>();
        foreach (var criterion in criteria)
        {                    
            ExpressionBuilder expressionBuilder = new ExpressionBuilder();
            var param = Expression.Parameter(typeof (T));
            Expression expression = expressionBuilder.BuildExpression<T>(criterion.PropertyName,
                    criterion.Operator_, criterion.Value, param);
            Func<T, bool> func = Expression.Lambda<Func<T, bool>>(expression, param).Compile();
            list.Add(func);
        }

        return list.ToArray();
    }

标准

public class Criterion
{
    private bool propertySet;
    public string PropertyName { get; set; }
    public Enums.Operator Operator_ { get; set; }
    public object Value { get; set; }

会员模型

public class MemberModel
{
    public string UserName{ get; set; }
    public PersonalDetailsModel PersonalDetails {get; set;}
}

PersonalDetailsModel

    public class PersonalDetailsModel
{
    public int PersonalDetailsId { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Middlename { get; set; }
    public string DateOfBirth { get; set; }
    public string GenderType { get; set; }
    public string SalutationType { get; set; }
}

当我尝试将嵌套属性作为左操作数(即 PropertyName="PersonalDetails.FirstName" 传递给 ruleEngine.CombineRules(criteria.ToArray()); 时出现问题

我得到“'PersonalDetails.Firstname' 不是'System.String' 类型的成员”,尽管它显然是这样。我已经被这个问题困扰了一段时间,知道可能是什么原因造成的吗?

任何帮助将不胜感激。

【问题讨论】:

    标签: c# .net lambda expression-trees


    【解决方案1】:

    这里

        Expression body = parameterExpression;
    
        foreach (var member in propertyName.Split('.'))
        {
            body = MemberExpression.Property(body, member);
        }
    

    你已经处理了属性路径,所以这个

      var leftOperand = MemberExpression.PropertyOrField(body, propertyName);
    

    毫无意义,是异常的来源。在您的示例中,body 包含类似 p.PersonalDetails.FirstName (String) 的内容,而上面的行正在尝试构建类似 p.PersonalDetails.FirstName.PersonalDetails.FirstName 的内容。

    请改用var leftOperand = body;

    您可以使用简单的方式缩短整个属性路径处理

    var leftOperand = propertyName.Split('.')
        .Aggregate((Expression)parameterExpression, Expression.PropertyOrField);
    

    【讨论】:

    • 天哪,多么愚蠢的疏忽。血腥的星期五。非常感谢!
    • 我们怎样才能为 List 实现同样的效果?
    • @VamsidharMamillapalli 这会动态构建(或可以构建)单项过滤器,例如Func&lt;PersonalDetailsModel, bool&gt;Expression&lt;Func&lt;PersonalDetailsModel, bool&gt;&gt;,可以分别传递给Where 的方法IEnumerable&lt;PersonalDetailsModel&gt;List&lt;PersonalDetailsModel&gt; 是)或IQueryable&lt;PersonalDetailsModel&gt;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 2022-06-12
    相关资源
    最近更新 更多