CSharp - 在使用表达式的属性和子属性上,比较对象

  显示原文与译文双语对照的内容
0 0

我有以下方法来比较 dto 。

bool Equals<T1, T2>(T1 t1, T2 t2, params Expression<Func<T1, object>>[] accessors)
{
 return!(
 from accessor in accessors 
 select ((MemberExpression) accessor.Body).Member.Name into propertyName 
 let p1 = typeof (T1).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) 
 let p2 = typeof (T2).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) 
 let p1val = p1.GetValue(t1, null) 
 let p2val = p2.GetValue(t2, null) 
 where!Equals(p1val, p2val) 
 select p1val
 ).Any();
}

我可以使用( ab 是按约定共享相同属性的对象的实例,但不是相同的对象) 来调用它:

Equals(a, b, x => x.PropertyOne, x => x.PropertyTwo );

通过属性比较对象的属性,这对于大多数情况是很好的。

但是,我发现需要比较具有复杂类型属性的对象,而我想比较复杂类型的属性。 像这样:

Equals(a, b, x => x.ComplexTypeProperty.ChildProp );

在这之前,我已经意识到了,我需要在comfy比较and输入表达式land但是主要任务是通过复杂类型属性和属性访问器( 这里是我丢失的属性访问器) 。

任何指针都是不错的,谢谢 !

时间:原作者:1个回答

0 0

这个任务并不复杂:

  1. 确定表达式给出的属性路径或者表达式。 例如这里扩展方法将向你提供:

    public static IEnumerable<string> GetPropertiesNames<T, G>(this Expression<Func<T, G>> pathExpression)
    {
     List<string> _propertyNames = new List<string>();
     Expression expression = pathExpression.Body;
     if (expression.NodeType == ExpressionType.Convert)
     {
     var convert = (UnaryExpression)pathExpression.Body;
     expression = convert.Operand;
     }
     while (expression.NodeType == ExpressionType.MemberAccess)
     {
     MemberExpression memberExpression = (MemberExpression)expression;
     if(!(memberExpression.Member is PropertyInfo)) 
     throw new InvalidOperationException();
     _propertyNames.Add(memberExpression.Member.Name);
     expression = memberExpression.Expression;
     }
     if (expression.NodeType!= ExpressionType.Parameter)
     throw new InvalidOperationException();
     return _propertyNames;
    }
  2. 用于创建将返回值的函数的第二个类型的聚合表达式:

    var parameter = Expression.Parameter(typeof(T2)); 
    var expressionToConvert = accessors[0];//for future loop
     var propertyChainDescriptor = expressionToConvert.GetPropertiesNames() 
    . Aggregate(new { Expression = (Expression)parameterCasted, Type = typeof(T2)},
     (current, propertyName) =>
     {
     var property = current.Type.GetProperty(propertyName);
     var expression = Expression.Property(current.Expression, property);
     return new { Expression = (Expression)expression, Type = property.PropertyType };
     });
     var body = propertyChainDescriptor.Expression;
     if (propertyChainDescriptor.Type.IsValueType)
     {
     body = Expression.Convert(body, typeof(object));
     }
     var t2PropertyRetriver = Expression.Lambda<Func<T2, object>>(body, parameter).Compile();
  3. 现在,执行检索值并比较的方法:

     var t1PropertyRetriver = accessor[0].Compile();
     var t1Value = t1PropertyRetriver(t1);
     var t2Value = t2PropertyRetriver(t2);
     var areEqual = object.Equals(t1Value,t2Value);

最好的办法是添加一些生成方法的缓存,因为编译过程很昂贵。

原作者:
...