检查两个未知类型的对象是否相等,比较所有字段

时间:2012-02-22 15:09:08

标签: c# reflection equality

我需要定义一个方法来比较同一类型的两个不同对象。对象的类型不是特定的。对象可能是DLL类型,因此我无法覆盖Equals方法。我必须通过反思来做到这一点。如果对象的所有成员都是基本类型,则此代码有效。但是当对象具有非原始字段时,它不起作用。我怎么能通过反思来做到这一点?

public bool Equals(object obj1, object obj2)
{
    List<FieldInfo> fieldInfos =  obj1.GetType().GetFields().ToList();
    return (fieldInfos.Select(fieldInfo => new {fieldInfo, type = fieldInfo.GetType()})
        .Where(@t => @t.type.IsPrimitive || @t.type == typeof(string) || @t.type == typeof(Decimal))
        .Select(@t => @t.fieldInfo)).All(fieldInfo => fieldInfo.GetValue(obj1).Equals(fieldInfo.GetValue(obj2)));
}

2 个答案:

答案 0 :(得分:5)

我最近被告知这个lib将完全符合您的要求

http://comparenetobjects.codeplex.com/releases/view/47978

答案 1 :(得分:0)

我希望实用程序功能比较任何2个对象。我想要涵盖的所有类型都是

  1. 原始类型
  2. 任何实现IEnumerable(如Dict或List)的类
  3. 任何类
  4. 所以我使用泛型和反射来做到这一点。我这样编码。

            public static bool CompareObjects<T>(T expectInput, T actualInput)
        {
            // If T is primitive type.
            if (typeof(T).IsPrimitive)
            {
                if (expectInput.Equals(actualInput))
                {
                    return true;
                }
    
                return false;
            }
    
            if (expectInput is IEquatable<T>)
            {
                if (expectInput.Equals(actualInput))
                {
                    return true;
                }
    
                return false;
            }
    
            if (expectInput is IComparable)
            {
                if (((IComparable)expectInput).CompareTo(actualInput) == 0)
                {
                    return true;
                }
    
                return false;
            }
    
            // If T is implement IEnumerable.
            if (expectInput is IEnumerable)
            {
                var expectEnumerator = ((IEnumerable)expectInput).GetEnumerator();
                var actualEnumerator = ((IEnumerable)actualInput).GetEnumerator();
    
                var canGetExpectMember = expectEnumerator.MoveNext();
                var canGetActualMember = actualEnumerator.MoveNext();
    
                while (canGetExpectMember && canGetActualMember && true)
                {
                    var currentType = expectEnumerator.Current.GetType();
                    object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(currentType).Invoke(null, new object[] { expectEnumerator.Current, actualEnumerator.Current });
    
                    if ((bool)isEqual == false)
                    {
                        return false;
                    }
    
                    canGetExpectMember = expectEnumerator.MoveNext();
                    canGetActualMember = actualEnumerator.MoveNext();
                }
    
                if (canGetExpectMember != canGetActualMember)
                {
                    return false;
                }
    
                return true;
            }
    
            // If T is class.
            var properties = typeof(T).GetProperties();
            foreach (var property in properties)
            {
                var expectValue = typeof(T).GetProperty(property.Name).GetValue(expectInput);
                var actualValue = typeof(T).GetProperty(property.Name).GetValue(actualInput);
    
                if (expectValue == null || actualValue == null)
                {
                    if (expectValue == null && actualValue == null)
                    {
                        continue;
                    }
    
                    return false;
                }
    
                object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(property.PropertyType).Invoke(null, new object[] { expectValue, actualValue });
    
                if ((bool)isEqual == false)
                {
                    return false;
                }
            }
    
            return true;
        }