簡體   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