Je viens d'un monde python où seuls les objets hashables peuvent être utilisés comme clés pour un dictionnaire. Y a-t-il une restriction similaire en C#? Peut-on utiliser des types personnalisés comme clés de dictionnaire?
Réponses
Trop de publicités?L'exigence pour une clé de dictionnaire est qu'elle soit comparable et hashable. C'est des tortues tout le long dans .NET, chaque type (autre que les types de pointeur) dérive de System.Object et est toujours comparable grâce à sa méthode Equals(). Et hashable grâce à sa méthode GetHashCode(). Donc tout type .NET peut automatiquement être utilisé comme clé.
Si vous voulez utiliser votre propre type comme clé, alors vous avez seulement besoin de faire quelque chose de spécial si vous voulez redéfinir l'identité de l'objet. En d'autres termes, si vous avez besoin de la capacité pour deux objets distincts d'être égaux. Vous devrez alors remplacer la méthode Equals(), en comparant généralement les champs de l'objet. Et ensuite vous devrez également remplacer GetHashCode(), les objets égaux doivent générer le même code de hachage.
Si le type ne peut pas être modifié ou si vous voulez personnaliser le comportement spécialement pour le Dictionnaire, alors vous pouvez passer un IEqualityComparer<> personnalisé au constructeur. Gardez à l'esprit que la qualité du code de hachage que vous générez avec votre propre GetHashCode() détermine l'efficacité du dictionnaire.
Oui, la chose importante avec les clés est qu'elles implémentent (ou ont une bonne implémentation par défaut) GetHashCode
et Equals
. L'implémentation de Dictionary
peut tirer parti de IEqualityComparer
générique.
Tous les types personnalisés seront fournis avec une implémentation par défaut de GetHashCode
et Equals
car ce sont des membres de object
, cependant, cette implémentation par défaut peut ne pas toujours être pertinente pour votre type.
Le dictionnaire tente d'abord d'obtenir le code de hachage pour déterminer le compartiment dans lequel la valeur se situera. En cas de collision de hachage, il se rabat sur l'égalité (je pense).
Notez que le type de clé que vous utilisez (class
, struct
, type primitif, etc.) peut avoir des caractéristiques de performance différentes. Dans notre base de code, nous avons constaté que l'implémentation par défaut de GetHashCode
dans struct
n'était pas aussi rapide que de le remplacer nous-mêmes. Nous avons également constaté que les dictionnaires imbriqués offrent de meilleures performances en termes de temps d'accès qu'un seul dictionnaire avec une clé composite.
Je voudrais ajouter que, de nos jours, vous pouvez utiliser des types record
C# comme clés.
L'avantage de record
(plutôt que de class
) est qu'il implémente maintenant GetHashCode()
etc. pour vous automatiquement (via une magie générée par le compilateur).
- Pour plus de détails, consultez Records (C# reference) -- Value equality
- Attention, cette aide ne mentionne pas explicitement que vous pouvez les utiliser comme clés (mais je pense que c'est possible)
- Attention, je m'attends à ce que des problèmes surviennent si vous mutez (changez la valeur d'une propriété d') un objet utilisé comme clé, donc ne le faites pas