【问题标题】:Expression trees , object comparer表达式树,对象比较器
【发布时间】:2011-05-21 15:46:34
【问题描述】:

我需要生成表达式树而不是检查两个对象(参数)是否相等。我知道这些对象会有属性,所以我要比较它们的值,怎么做呢? 所以我有类似obj1obj2 和我需要检查的属性名称的字符串数组。 这是我的看法:

var leftObject = E.Parameter(typeof (object), "leftObject");
var rightObject = E.Parameter(typeof (object), "rightObject");
var properties = E.Parameter(typeof (string[]), "properties");
var i = E.Parameter(typeof(int), "i");
var equal = E.Parameter(typeof (bool), "equal");

var body = E.Block
    (
        new[] { properties, i},
        E.Assign(properties,E.Constant(props)),
        E.Assign(i,E.Constant(0)),
        E.Assign(equal,E.Constant(true)),

        E.Loop
        (
            E.Property(leftObject,props[i]) == E.Property(rightObject,props[i])
        )
    );

如何在Loop中实现对属性的一一访问?

附: E 是我的别名 Expression

【问题讨论】:

    标签: c# expression-trees


    【解决方案1】:

    您可以使用反射来做到这一点。

    bool eq = true;
    foreach (string prop in PropertiesYouWantToCheck){
        PropertyInfo propInfo = obj1.GetType().GetProperties().Single(x => x.Name == prop);
        if(propInfo.GetValue(obj1, null) != propInfo.GetValue(obj2, null)){
            eq = false;
            break;
        }
    }
    

    如果您使用上述方法,请确保将字符串转换为字符串而不是对象。

     string[] props = null;
     var leftObject = Expression.Parameter(typeof(object), "leftObject");
     var rightObject = Expression.Parameter(typeof(object), "rightObject");
     var equal = Expression.Variable(typeof(bool), "equal");
     var lbl = Expression.Label();
     var returnTarget = Expression.Label();
    
     var body = Expression.Block
      (
       typeof(bool),
       equal,
       Expression.Assign(equal, Expression.Constant(true)),
    
       Expression.Block(
        props.Select(property =>
          Expression.IfThen(
           Expression.NotEqual(Expression.Property(leftObject, property),
                Expression.Property(rightObject, property)),
           Expression.Block(
            Expression.Assign(equal, Expression.Constant(false)),
            Expression.Goto(lbl)
           )
          )
         )
       ),
    
       Expression.Label(lbl),
       Expression.Return(returnTarget, equal, typeof(bool)),
       Expression.Label(returnTarget)
      );
    

    【讨论】:

    • 谢谢。我已经使用反射完成了,但是它非常慢,所以我决定为不同的对象生成比较方法并将它们编译到内存中,而不是检查比较方法预设类型存在,只需调用它。它比反射快一百倍,因为我需要比较的每种类型都会编译一次表达式。
    【解决方案2】:

    您应该使用反射来发现您想要的属性,然后基本上创建一大系列 AndAlso 表达式。 例如

        public static Func<T, T, bool> BuildStructuralComparerDelegate<T>() where T:class
        {
            var left = Expression.Parameter(typeof(T), "left");
            var right = Expression.Parameter(typeof(T), "right");
            var referenceEquals = typeof(object).GetMethod("ReferenceEquals");
            Expression expression = Expression.AndAlso(
                Expression.Not(
                    Expression.Call(
                        null,
                        referenceEquals,
                        left,
                        Expression.Default(typeof(T))
                    )
                ),
                Expression.Not(
                    null,
                    Expression.Call(
                        referenceEquals,
                        right,
                        Expression.Default(typeof(T))
                    )
                )
            );
            Array.ForEach(typeof(T).GetProperties(),property =>
                expression = Expression.AndAlso(
                    expression,
                    Expression.Equal(
                        Expression.Property(left, property),
                        Expression.Property(right, property)
                    )
                )
            );
            var lambdaExp = Expression.Lambda<Func<T, T, bool>>(
                Expression.OrElse(
                    Expression.Call(
                        null,
                        referenceEquals,
                        left,
                        right
                    ),
                    expression
                ),
                left,
                right
            );
            return lambdaExp.Compile();
        }
    

    上面的代码只适用于类,创建一个大致的表达式

    (left,right)=> object.ReferenceEquals(left,right) || (left != null && right != null && left.Property1 == right.Property1 && left.Property2 == right.Property2 && ... && left.PropertyN == right.PropertyN);
    

    这不是一个完整的解决方案,因为它假定您要比较所有属性并且所有属性都是可读的,但它应该让您走上正轨。如果您关心这些事情,它也与 .NET 3.5 兼容。

    【讨论】:

      【解决方案3】:
      猜你喜欢
      • 2016-01-31
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多