繁体   English   中英

在通用.Equals方法中比较两个数组

[英]Comparing two arrays in a generic .Equals method

请参见下面的代码:

 public virtual bool Equals(T other)
            {
                if (other == null)
                    return false;
                Type t = GetType();
                Type otherType = other.GetType();
                if (t != otherType)
                    return false;
                FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                foreach (FieldInfo field in fields)
                {
                    object value1 = field.GetValue(other);
                    object value2 = field.GetValue(this);
                    if (value1 == null)
                    {
                        if (value2 != null)
                           return false;
                    }
                    else if (!value1.Equals(value2))
                        return false;
                }
                return true;
            }

假设value1和value2是字符串数组。 即使数组具有相同的内容,上面的代码也会返回false。 如果它们包含相同的内容,如何确保返回true?

我在这里看过: 如何在C#中比较数组? 并尝试了这个:

bool isEqual = Enumerable.SequenceEqual(value1, value2);

编译器错误是:无法从使用情况推断出SequenceEqual。

问题的一部分是field.GetValue(other)返回一个object 您可能会发现,使用递归反射来比较未类型化的对象会让您感到沮丧。

为了使此工作有效,您必须确定该字段是否为集合,如果是,则比较该集合的内容。 那么如果其中一个集合包含一个集合怎么办? 这是可行的,但令人头疼。

无论您要尝试比较的对象是什么,如果实现IEquatable<T>或为要比较的类型定义IEqualityComparer<T> ,它都会更加简单。 然后,您的Equals方法显式检查各个成员的相等性。 如果这些成员是引用类型,则也要为它们定义相等性。 然后,如果这些类型具有更多的嵌套属性,则无需深入研究所有这些嵌套属性并比较它们的属性。

这最终需要的是您的方法“知道”正在比较的类型,以便确切知道如何比较它们。 如果您使用反射来找出属性是什么,然后尝试检查它们是否相等,则可以,但是很困难,并且可能会被将来的更改破坏。

这是一个使用一些带有嵌套属性的类的示例。

public class Foo : IEquatable<Foo>
{
    public int FooValue { get; set; }
    public List<Bar> Bars { get; set; }

    public bool Equals(Foo other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        if (FooValue != other.FooValue) return false;
        if (Bars == null ^ other.Bars == null) return false;
        return Bars == null || Bars.SequenceEqual(other.Bars);
    }
}

public class Bar : IEquatable<Bar>
{
    public int BarValue { get; set; }
    public List<FooBar> FooBars { get; set; }

    public bool Equals(Bar other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        if( BarValue != other.BarValue) return false;
        if (FooBars == null ^ other.FooBars == null) return false;
        return FooBars==null || FooBars.SequenceEqual(other.FooBars);
    }
}

public class FooBar : IEquatable<FooBar>
{
    public int FooBarValue { get;  set; }

    public bool Equals(FooBar other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return FooBarValue == other.FooBarValue;
    }
}

每个具有嵌套集合属性的类都使用SequenceEqual来确定集合是否匹配。 但是,如何确定这些集合中的各个项目是否彼此相等? 没有。 它假定这些类型将能够确定相等性。

现在,如果使一个类的两个实例相等的条件发生了变化,则可以将详细信息隔离到该类。

假设我无法修改其中一个类来支持IEquatable<T> ,或者由于某种原因,这样做是没有意义的。 也许在不同情况下平等是不同的。 也许一个类具有ID属性,并且在某些情况下,我关心的是如果两个对象具有相同的ID ,则它们相等。

在那种情况下,我可以将该相等比较移到其自己的类中,并且仅在需要时使用它。 它不再“内置”在班级中。

public class FooBar 
{
    public int FooBarValue { get; set; }
}

public class FooBarComparer : IEqualityComparer<FooBar>
{
    public bool Equals(FooBar x, FooBar y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.FooBarValue == y.FooBarValue;
    }

    public int GetHashCode(FooBar obj)
    {
        return obj.GetHashCode();
    }
}

现在,当我在FooBar两个集合上使用SequenceEqual时,我将执行以下操作:

FooBars.SequenceEqual(other.FooBars, new FooBarComparer())

这样做的另一个好处是,您可以重复使用相等比较。 假设您有两个带有Bar列表的不同类。 现在,这两个类都不必检查Bar及其嵌套属性来确定相等性,这将重复代码。 该相等性检查位于其他位置,并且可以在需要时由两者共享。

这个问题很可能与引用相等vs价值相等有关。 如果比较两个不覆盖等于的对象,则表示它们是同一项目,但值不同。

您看到的SequenceEqual错误与编译器有关,无法确定您要比较的类型。
https://msdn.microsoft.com/en-us/library/bb348567(v=vs.110).aspx

您可以指定要用于检查相等性的类型

bool isEqual = Enumerable.SequenceEqual<T>(value1, value2);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM