通用平等检查员

时间:2017-04-18 23:41:11

标签: c# equality

我正在维护一个代码库,我找到了两个扩展方法,处理检查对象的结构相等性,我根本不喜欢(一个调用另一个):

public static bool IsObjectEqual<T>(this T obj, T obj2)
{
    foreach (var pi in obj.GetType().GetProperties())
    {
        var enumerable1 = pi.GetValue(obj, null) as IEnumerable;
        var enumerable2 = pi.GetValue(obj2, null) as IEnumerable;

        if (enumerable1 != null)
        {
            foreach (var item in enumerable1)
            {
                if (enumerable2 == null || !((object[])enumerable2).Contains(item))
                {
                    return false;
                }

            }
        }
        else if (!IsPropertyInfoValueEqual(pi, obj, obj2))
        {
            return false;
        }
    }

    return true;
}

private static bool IsPropertyInfoValueEqual<T>(PropertyInfo pi, T obj, T obj2)
{
    var val = pi.GetValue(obj, null);
    var val2 = pi.GetValue(obj2, null);

    if (val != null && val2 != null)
    {
        return val.Equals(val2);
    }

    return (val == null && val2 == null);
}

问题是,我遇到了一个我认为会失败或导致问题的情况。我知道在我的水域里他们错了,我只是不能把手指放在上面。

我在实现相等性检查时总是使用IEquateable<T>,因此缺少任何处理相等性的框架类/接口是调用我的蜘蛛感官的一件事。我意识到这种方法试图成为一种基于反射的广义方法,但它让我感到紧张(如上所述)。

有人能看到这些方法的合法问题吗?

修改

方法的大合法问题。对object []的强制转换导致InvalidCastException。

1 个答案:

答案 0 :(得分:1)

可能还有其他人,但我发现此代码有两个主要问题:

  1. 反思很昂贵。真的很贵。如此大规模地使用它来进行简单检查这样简单的事情只是一个坏主意。代码甚至不缓存对象图,因此它必须每次完成全部反射。在相当常见的情况下,我可以看到这种方法是性能瓶颈。

  2. 如果成员为IEnumerable,则代码将无法按预期工作。其他所有内容都与反射进行比较,但使用Contains比较集合。这将执行简单的引用相等(至少对于引用类型),并且不重用反射方法。这可能会导致此方法的用户产生不良结果。

  3. 实施IEquatable和朋友是一种更快,更安全的方法。实现者可以明确决定比较的工作方式,而且不需要任何反射。