比较复杂对象

本文关键字:对象 复杂 比较 | 更新日期: 2023-09-27 18:35:22

我需要写一个比较器来比较各种类型的复杂对象,我写了一些代码,但对我来说似乎太长了,那么有两个复杂对象之间有没有其他很好的比较方法?

我的代码:

class CompareObjOfType
{
    private static int _totalFalseCount;
    public static bool CompareObjectsOfType(Type T, object source, object target)
    {
        bool result = false;
        if ((source == null) && (target == null))
        {
            return true;
        }
        if ((source == null) ^ (target == null))
        {
            _totalFalseCount++;
            return false;
        }
        if (T.IsValueType || (T == typeof(string)))
        {
            if (T == typeof(DateTime))
            {
                if (!(((DateTime)source).ToUniversalTime().Equals(((DateTime)target).ToUniversalTime())))
                {
                    _totalFalseCount++;
                    return false;
                }
            }
            else if (T == typeof(string))
            {
                if (string.IsNullOrEmpty((string)source) ^ string.IsNullOrEmpty((string)target))
                {
                    _totalFalseCount++;
                    return false;
                }
                if (!(string.IsNullOrEmpty((string)source) && string.IsNullOrEmpty((string)target)))
                {
                    _totalFalseCount++;
                    return false;
                }
                if (!(((string)source).Equals((string)target)))
                {
                    _totalFalseCount++;
                    return false;
                }
            }
            else
            {
                if (!(source.ToString().Equals(target.ToString())))
                {
                    _totalFalseCount++;
                    return false;
                }
            }
            return true;
        }
        else
        {
            var properties = T.GetProperties();
            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsArray || propertyType.IsGenericType)
                {
                    var sourceValue = property.GetValue(source);
                    var targetValue = property.GetValue(target);
                    if ((sourceValue == null) && (targetValue == null))
                    {
                        result = true;
                        continue;
                    }
                    if ((sourceValue == null) ^ (targetValue == null))
                    {
                        _totalFalseCount++;
                        result = false;
                        continue;
                    }
                    var sourceCount = ((IList)sourceValue).Count;
                    var targetCount = ((IList)targetValue).Count;
                    if (sourceCount != targetCount)
                    {
                        _totalFalseCount++;
                        result = false;
                        continue;
                    }
                    for (int i = 0; i < sourceCount; i++)
                    {
                        Type elementType = propertyType.IsArray
                                               ? propertyType.GetElementType()
                                               : propertyType.GetGenericArguments().First();
                        result = CompareObjectsOfType(elementType, ((IList)sourceValue)[i],
                                                      ((IList)targetValue)[i]);
                    }
                }
                else
                {
                    result = CompareObjectsOfType(propertyType, property.GetValue(source), property.GetValue(target));
                }
            }
        }
        return result;
    }
}

比较复杂对象

我在测试中经常使用此代码。它绝不完美,但可能足够好。 请注意,忽略参数可以包含您不想比较的属性名称列表。

    public static void AssertArePropertiesEqual<T>(T expectedObj, T actualObj, params string[] ignore) where T : class
    {
        if (expectedObj != null && actualObj != null)
        {
            var type = typeof(T);
            if (type.IsPrimitive || type == typeof(string))
            {
                Assert.AreEqual(expectedObj, actualObj);
                return;
            }
            var ignoreList = new List<string>(ignore);
            foreach (var pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (ignoreList.Contains(pi.Name)) continue;
                var selfValue = type.GetProperty(pi.Name).GetValue(expectedObj, null);
                var toValue = type.GetProperty(pi.Name).GetValue(actualObj, null);
                var selfValueDate = selfValue as DateTime?;
                var toValueDate = toValue as DateTime?;
                if (selfValueDate.HasValue && toValueDate.HasValue)
                {
                    Assert.IsTrue(Math.Abs((selfValueDate.Value - toValueDate.Value).TotalSeconds) < 1,
                                  string.Format("The compare of [{0}] properties failed. Expected Date:{1}  Actual Date: {2}", pi.Name,
                                                selfValueDate, toValueDate));
                }
                else
                {
                    Assert.AreEqual(selfValue, toValue, string.Format("The compare of [{0}] properties failed.", pi.Name));
                }
            }
            return;
        }
        Assert.AreEqual(expectedObj, actualObj);
    }

实现 IComparer。在msdn上有一个示例,在万维网上也有很多示例。

您需要检查的只是第一个对象在语义上是否被视为小于等于大于第二个对象。

然后,可以轻松地在 LINQ 查询中或需要对对象进行排序的任何位置对对象进行排序。

但是,最好重新考虑类的设计。很少需要这种广泛的比较(如在您的代码中)。


如果你只需要检查相等性(不小于大于),那么一个IEqualityComparer比较器就足够了,正如Kris所评论的那样。