2 votes

EqualityComparer sur un objet imbriqué

Je voudrais comparer deux listes d'objets imbriqués. Si les objets parents Id différer et/ou l'un des enfants Id o Baz les propriétés diffèrent, je veux les considérer comme modifiées.

J'ai implémenté ma propre version de Equals y GetHashCode ci-dessous, mais malgré l'utilisation de mon propre comparateur d'égalité, Except() donne toujours un résultat, alors que je m'attends à ce que les objets soient égaux.

var foo1 = new Foo
{
    Id = 1,
    Bars = new List<Bar>
    {
        new Bar
        {
            Id = 1,
            Baz = 1.5
        },
        new Bar
        {
            Id = 1,
            Baz = 1.5
        }
    }
};

var foo2 = new Foo
{
    Id = 1,
    Bars = new List<Bar>
    {
        new Bar
        {
            Id = 1,
            Baz = 1.5
        },
        new Bar
        {
            Id = 1,
            Baz = 1.5
        }
    }
};

var diff = new[] { foo1 }.Except(new[] { foo2 });

public class Foo
{
    private sealed class IdBarsEqualityComparer : IEqualityComparer<Foo>
    {
        public bool Equals(Foo x, Foo y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(x, null)) return false;
            if (ReferenceEquals(y, null)) return false;
            if (x.GetType() != y.GetType()) return false;
            return x.Id == y.Id && Equals(x.Bars, y.Bars);
        }

        public int GetHashCode(Foo obj)
        {
            unchecked
            {
                return (obj.Id * 397) ^ (obj.Bars != null ? obj.Bars.GetHashCode() : 0);
            }
        }
    }

    public static IEqualityComparer<Foo> IdBarsComparer { get; } = new IdBarsEqualityComparer();

    public int Id { get; set; }
    public List<Bar> Bars { get; set; }
}

public class Bar
{
    protected bool Equals(Bar other)
    {
        return Id == other.Id && Baz.Equals(other.Baz);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Bar) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (Id * 397) ^ Baz.GetHashCode();
        }
    }

    public int Id { get; set; }
    public double Baz { get; set; }
}

4voto

Selman22 Points 44788

Il y a trois choses qui ne vont pas dans votre code :

  1. Vous ne passez pas le comparateur d'égalité à Except donc elle n'est pas utilisée.
  2. Votre GetHashCode la mise en œuvre dans Foo est erronée, elle renvoie des résultats différents pour les mêmes objets, donc la fonction Equals n'est jamais appelée.
  3. Vous appelez des égaux sur deux listes : Equals(x.Bars, y.Bars) ce qui permet de vérifier l'égalité des références. Vous pouvez utiliser SequenceEqual au lieu de comparer les éléments un par un : x.Bars.SequenceEqual(y.Bars)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X