web-dev-qa-db-fra.com

Comparer un objet utilisé comme clé dans le dictionnaire

ma classe:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
}

et exemple principal:

Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
myClass first = new myClass();
first.A = 2;
first.B = 3;

myClass second = new myClass();
second.A = 2;
second.B = 3;
second.C = 5;
second.D = 6;

dict.Add(first, new List<string>());

if (dict.ContainsKey(second))
{
    //
    //should come here and update List<string> for first (and only in this example) key 
    //
}
else
{
    //
    //if myFirst object has difference vlues of A or B properties
    //
    dict.Add(second, new List<string>());
}

Comment faire ça?

19
Saint

Si vous voulez toujours que le dictionnaire ne compare que sur A et B, vous avez deux options. Soit tilisez le constructeur qui implémente IEqualityComparer<TKey> et y mettre votre logique de comparaison, ou faire implémenter votre classe IEquateable<T> GetHashCode and Equals pour que le comparateur par défaut vous donne les résultats que vous recherchez.

Si vous voulez seulement comparer sur A et B dans votre situation, vous devrez utiliser la propriété .Keys et la méthode d'extension Linq Contains qui vous permet de passer un IEqualityComparer<T>. Cependant, lorsque vous le faites de cette façon, vous perdez les avantages de la vitesse d'utilisation d'un dictionnaire, alors utilisez-le avec parcimonie.

public class MyClassSpecialComparer : IEqualityComparer<myClass>
{
    public bool Equals (myClass x, myClass y)
    { 
        return x.A == y.A && x.B == y.B 
    }

    public int GetHashCode(myClass x)
    {
       return x.A.GetHashCode() + x.B.GetHashCode();
    }


}


 //Special case for when you only want it to compare this one time
 //NOTE: This will be much slower than a normal lookup.
    var myClassSpecialComparer = new MyClassSpecialComparer();
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
    //(Snip)
    if (dict.Keys.Contains(second, myClassSpecialComparer ))
    {
        //
        //should come here and update List<string> for first (and only in this example) key 
        //
    }

 //If you want it to always compare
    Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>(new MyClassSpecialComparer());
30
Scott Chamberlain

Par défaut, la comparaison place les objets dans des compartiments en fonction de leur code de hachage. Une comparaison détaillée est ensuite effectuée (en appelant Equals) si deux codes de hachage sont identiques. Si votre classe ne fournit ni GetHashCode ni n'implémente l'égalité, la valeur par défaut object.GetHashCode sera utilisé - auquel cas rien de spécifique à votre classe ne sera utilisé pour la sémantique de comparaison de valeurs. Seule la même référence sera trouvée. Si vous ne le souhaitez pas, implémentez GetHashCode et implémentez l'égalité.

Par exemple:

public class myClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }

    public bool Equals(myClass other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.A == A && other.B == B && other.C == C && other.D == D;
    }

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

    public override int GetHashCode()
    {
        unchecked
        {
            int result = A;
            result = (result*397) ^ B;
            result = (result*397) ^ C;
            result = (result*397) ^ D;
            return result;
        }
    }
}
7
Peter Ritchie

Remplacez votre myClass:

  • Méthode GetHashCode

  • Méthode égale

Pour implémenter la méthode GetHashCode, vous pouvez simplement XOR GetHashCodes à partir de vos propriétés entières.

Substituez éventuellement la méthode ToString et implémentez l'interface IEquatable

4
Regfor