C# 在泛型.Equals方法中比较两个数组

C# 在泛型.Equals方法中比较两个数组,c#,.net,C#,.net,请参阅下面的代码: public virtual bool Equals(T other) { if (other == null) return false; Type t = GetType(); Type otherType = other.GetType(); if (t != otherType

请参阅下面的代码:

 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

我看了这里,试了一下:

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

编译器错误是:无法从用法推断SequenceEqual。

问题很可能与引用相等与值相等有关。如果比较两个不覆盖等于的对象,则比较的是它们是相同的项而不是相同的值

您看到的SequenceEqual错误与编译器不确定用于比较的类型有关。

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


bool isEqual=可枚举的.SequenceEqualvalue1,value2

部分问题在于field.GetValueother返回一个对象。您可能会发现,使用递归反射来比较非类型化对象会让您感到沮丧

为了实现这一点,您必须确定字段是否为集合,如果是,则比较集合的内容。那么,如果其中一个集合包含一个集合呢?这是可行的,但令人头痛

无论您试图比较的对象是什么,如果您为要比较的类型实现或定义一个对象,则会简单得多。然后,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;
    }
}
这最终需要的是,您的方法知道要比较的类型,以便确切地知道如何比较它们。如果您使用反射来确定属性是什么,然后尝试检查它们是否相等,这是可能的,但这很困难,并且可能会被未来的更改破坏

下面是一个使用几个具有嵌套属性的类的示例

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;
    }
}
现在,当我在两个FooBar集合上使用SequenceEqual时,我会这样做:

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

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

有关此通用相等的内容,请参见此处:@Tim Schmelter,我使用类似的方法对数据类上的复制或克隆运算符进行单元测试。请粘贴实际错误。以及产生it@pm100,我有。请看最后一行。我不能这样做,因为value1和value2是对象而不是数组。然后尝试将其预先转换,如果不可能,它将返回null:value1作为数组或更好的value1作为IEnumerableThanks+1以供IEquatable和IEqualityComparer参考。请在这里查看我问题的答案:。回答者说:让实现调用库方法。。这对我来说是可行的。你能修改你的代码吗?你可以创建一个扩展方法,比如static bool equals这个Foo foo1,Foo f2,然后把你的比较放在那里。如果有好处或需要,该类甚至可以位于另一个项目库中的方法中。其要点是,检查一个类的两个实例之间是否相等的代码不需要在类本身中。您如何知道它是一个正在传递的foo类型?您在最后一条评论中指定了foo。它可能是任何东西。谢谢。在这个例子中,扩展是基于参数的Foo。如果您想为不同的类型编写一个方法,那么您可以为该类型编写一个方法。它有更多的方法,但是为一种类型编写的方法将是准确的。尝试处理所有不同类型的相等性的方法将有问题。