0

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

我的代码:

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;
    }
}
4

2 回答 2

1

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

    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);
    }
于 2013-10-15T20:43:34.477 回答
0

实施IComparer。msdn 上有一个例子,万维网上有很多例子。

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

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

但是,重新考虑类的设计可能会更好。很少需要如此广泛的比较(如在您的代码中)。


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

于 2013-10-15T16:08:13.713 回答