如何比较除null属性之外的两个对象?

时间:2018-05-04 19:47:30

标签: c#

我正在尝试编写一个比较对象的两个实例的属性的方法,这两个注意事项:1)对象通常会有其他复杂对象作为属性,甚至是其他复杂对象的数组,以及2)如果对象的一个​​实例上的属性为null,请不要担心对象的其他实例是否具有值。基本上,这样的事情(参见代码底部的预期结果):

public class Car
{
    public string make { get; set; }
    public string model { get; set; }
    public Option[] options { get; set;}

    public bool MagicCompare(Car obj)
    {
        // Do magic comparison
    }
}

public class Option
{
    public string name { get; set; }
    public string value { get; set; }
}

Car c1 = new Car
{
    make = "ford";
    model = "F-150";
    options = new[]
    {
        new Option {name = "seats", value = "leather"},
        new Option {name = "radio", value = "XM"}
    }
};

Car c2 = new Car
{
    make = "ford";
    model = "F-150";
};

Car c3 = new Car
{
    make = "ford";
    model = "mustang";
    options = new[]
    {
        new Option {name = "seats", value = "leather"},
        new Option {name = "radio", value = "XM"}
    }
};

Car c4 = new Car
{
    make = "ford";
    model = "F-150";
    options = new[]
    {
        new Option {name = "seats", value = "leather"}
    }
};

c1.MagicCompare(c2); // would return true, since all non-null properties match
c1.MagicCompare(c3); // would return false, since all non-null properties do NOT match
c1.MagicCompare(c4); // would return false, since the options array doesn't match

1 个答案:

答案 0 :(得分:0)

网上有很多针对C#的深度比较器实现。

此代码实现了一个处理几个字段或属性类型的代码,任何实现IEquatableICollection的代码。您需要添加其他类型,因为如果您有例如,它可能会爆炸自制的List类型,未实施ICollection

public static class Ext {
    public static bool HasDeclaredEquals(this object obj) =>
        typeof(IEquatable<>).MakeGenericType(obj.GetType())
                            .IsAssignableFrom(obj.GetType());
}

public class JSONCollectionComparer : IEqualityComparer {
    public new bool Equals(object x, object y) {
        var c = new JSONComparer();

        var xc = x as ICollection;
        var yc = y as ICollection;

        if (xc.Count != yc.Count)
            return false;

        var ans = true;
        foreach (var xyv in xc.Cast<object>().Zip(yc.Cast<object>(), (xv, yv) => (xv, yv))) {
            ans = ans && c.Equals(xyv.xv, xyv.yv);
            if (!ans)
                break;
        }

        return ans;
    }

    public int GetHashCode(object obj) {
        throw new NotImplementedException();
    }
}

public class JSONComparer : IEqualityComparer {
    public new bool Equals(object x, object y) {
        JSONComparer jc = null;
        JSONCollectionComparer jac = null;
        var ans = true;

        var members = x.GetType().GetMembers().Where(m => m is PropertyInfo || m is FieldInfo);
        foreach (var m in members) {
            var mType = m.GetMemberType();
            var xv = m.GetValue(x);
            var yv = m.GetValue(y);
            if (xv != null && yv != null)
                if (xv.HasDeclaredEquals())
                    ans = ans && xv.Equals(yv);
                else {
                    switch (xv) {
                        case ICollection xc:
                            jac = jac ?? new JSONCollectionComparer();
                            ans = ans && jac.Equals(xv, yv);
                            break;
                        default:
                            jc = jc ?? new JSONComparer();
                            ans = ans && jc.Equals(xv, yv); ;
                            break;
                    }
                }
            if (!ans)
                break;
        }

        return ans;
    }

    public int GetHashCode(object obj) {
        throw new NotImplementedException();
    }
}

现在你的MagicCompare很简单:

public bool MagicCompare(Car obj) {
    // Do magic comparison
    return new JSONComparer().Equals(this, obj);
}