繁体   English   中英

表达式树,对象比较器

[英]Expression trees , object comparer

我需要生成表达式树,然后检查两个对象(参数)是否相等。 我知道这些对象将具有属性,因此我必须比较它们的值,该怎么做? 所以我有一些类似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])
        )
    );

如何实现在循环中一对一地访问属性?

PS E是我对Expression别名。

您应该使用反射来发现所需的属性,然后基本上创建一系列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兼容。

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

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)
  );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM