Comparaisons clés pour Linq GroupBy à l'aide EqualityComparer par défaut
-
18-09-2019 - |
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 TypeT
implémente la interface génériqueSystem.IEquatable<T>
et si les rendements si unEqualityComparer<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
}
}
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);
}