C# 使用表达式比较属性和子属性上的对象
我有以下方法来比较DTOC# 使用表达式比较属性和子属性上的对象,c#,expression-trees,expression,C#,Expression Trees,Expression,我有以下方法来比较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 =
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();
}
它按属性比较对象属性,这在大多数情况下都很好
但是,我发现了这样一种情况:我需要比较具有复杂类型属性的对象,并且我希望比较复杂类型而不是对象的属性。大概是这样的:
Equals(a, b, x => x.ComplexTypeProperty.ChildProp );
我已经意识到,我需要离开舒适的反射比较,进入Expression land,但这里的主要任务是能够通过复杂类型的属性来表达属性访问器和属性访问器,这就是我丢失的地方
任何指示都很好,谢谢 任务没有那么复杂:
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;
}
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;
}
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();
var t1PropertyRetriver = accessor[0].Compile();
var t1Value = t1PropertyRetriver(t1);
var t2Value = t2PropertyRetriver(t2);
var areEqual = object.Equals(t1Value,t2Value);