Question

Je suis en train de faire un GroupBy Linq sur certains objets en utilisant un type de clé explicite. Je ne suis pas le passage d'un IEqualityComparer au GroupBy, donc selon les docs:

  

L'égalité par défaut Default comparateur est utilisé pour comparer les clés.

Il explique la propriété EqualityComparer<T>.Default comme ceci:

  

Les contrôles de propriété Default si   Type T implémente la   interface générique System.IEquatable<T>   et si les rendements si un   EqualityComparer<T> qui utilise ce   la mise en œuvre.

Dans le code ci-dessous, je groupant un tableau d'objets de Fred. Ils ont un type de clé appelé FredKey, qui met en œuvre IEquatable<FredKey>.

Cela devrait être suffisant pour faire le travail de regroupement, mais le groupe ne fonctionne pas. Dans la dernière ligne ci-dessous, je devrais avoir 2 groupes, mais je ne suis pas, je viens de 3 groupes contenant les 3 éléments d'entrée.

Pourquoi le groupement ne fonctionne pas?

class Fred
{
    public string A;
    public string B;
    public FredKey Key
    {
        get { return new FredKey() { A = this.A }; }
    }
}

class FredKey : IEquatable<FredKey>
{
    public string A;
    public bool Equals(FredKey other)
    {
        return A == other.A;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var f = new Fred[]
        {
            new Fred {A = "hello", B = "frog"},
            new Fred {A = "jim", B = "jog"},
            new Fred {A = "hello", B = "bog"},
        };

        var groups = f.GroupBy(x => x.Key);
        Debug.Assert(groups.Count() == 2);  // <--- fails
    }
}
Était-ce utile?

La solution

De MSDN

  

Si vous implémentez IEquatable, vous devez également remplacer les implémentations de classe de base de l'objet :: equals (Object) et GetHashCode () afin que leur comportement est conforme à celle de la IEquatable :: méthode Equals. Si vous faites passer outre l'objet :: equals (Object), l'implémentation surchargée est aussi appelé dans les appels à la méthode Equals statiques (System.Object, System.Object) sur votre classe. Cela garantit que toutes les invocations des méthode Equals () renvoient des résultats cohérents.

ajouter à FredKey et il devrait fonctionner

public override int GetHashCode()
    {
        return A.GetHashCode();
    }

Autres conseils

Voici un exemple complet avec un Fiddle. Remarque: l'exemple diffère légèrement de l'exemple de la question.

La mise en œuvre suivante IEquatable peut agir comme TKey GroupBy . Notez qu'il comprend à la fois GetHashCode et Equals.

public class CustomKey : IEquatable<CustomKey>
{
    public string A { get; set; }
    public string B { get; set; }

    public bool Equals(CustomKey other)
    {
        return other.A == A && other.B == B;
    }

    public override int GetHashCode()
    {
        return string.Format("{0}{1}", A, B).GetHashCode();
    }
}

public class Custom
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
}

public static void Main()
{
    var c = new Custom[]
       {
           new Custom {A = "hello", B = "frog" },
           new Custom {A = "jim", B = "jog" },
           new Custom {A = "hello", B = "frog" },
       };

    var groups = c.GroupBy(x => new CustomKey { A = x.A, B = x.B } );
       Console.WriteLine(groups.Count() == 2);  
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top