Je travaille sur un projet C # sur lequel, jusqu'à présent, j'ai utilisé des objets et des usines immuables pour m'assurer que les objets de type Foo
peuvent toujours être comparés pour égalité avec ==
.
Foo
les objets ne peuvent pas être modifiés une fois créés, et la fabrique renvoie toujours le même objet pour un ensemble d'arguments donné. Cela fonctionne très bien, et tout au long de la base de code, nous supposons que ==
fonctionne toujours pour vérifier l'égalité.
Maintenant, je dois ajouter des fonctionnalités qui introduisent un boîtier Edge pour lequel cela ne fonctionnera pas toujours. La chose la plus simple à faire est de surcharger operator ==
pour ce type, afin qu'aucun autre code du projet ne doive être modifié. Mais cela me semble être une odeur de code: surcharge operator ==
et non Equals
semble juste bizarre, et je suis habitué à la convention que ==
vérifie l'égalité des références et Equals
vérifie l'égalité des objets (ou quel que soit le terme).
Est-ce une préoccupation légitime, ou devrais-je simplement aller de l'avant et surcharger operator ==
?
Je crois que la norme est que pour la plupart des types, .Equals vérifie la similitude des objets et l'opérateur ==
vérifie l'égalité de référence.
Je pense que la meilleure pratique est que pour les types immuables, l'opérateur ==
devrait vérifier la similitude, ainsi que .Equals
. Et si vous voulez savoir s’il s’agit bien du même objet, utilisez .ReferenceEquals
. Voir la classe C # String
pour un exemple de cela.
Il y a une grande différence entre surcharge==
et prioritaire Égale.
Quand vous avez l'expression
if (x == y) {
La méthode qui sera utilisée pour comparer les variables x et y est décidée à compilation temps. Il s'agit d'une surcharge de l'opérateur. Le type utilisé lors de la déclaration de x et y est utilisé pour définir la méthode utilisée pour les comparer. Le type réel dans x et y (c'est-à-dire une sous-classe ou une implémentation d'interface) n'est pas pertinent. Considérer ce qui suit.
object x = "hello";
object y = 'h' + "Ello"; // ensure it's a different reference
if (x == y) { // evaluates to FALSE
et ce qui suit
string x = "hello";
string y = 'h' + "Ello"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
Cela démontre que le type utilisé pour déclarer les variables x et y est utilisé pour déterminer quelle méthode est utilisée pour évaluer ==.
Par comparaison, Equals est déterminé à runtime en fonction du type réel dans la variable x. Equals est une méthode virtuelle sur Object que d'autres types peuvent, et font, remplacer. Par conséquent, les deux exemples suivants ont tous les deux la valeur true.
object x = "hello";
object y = 'h' + "Ello"; // ensure it's a different reference
if (x.Equals(y)) { // evaluates to TRUE
et ce qui suit
string x = "hello";
string y = 'h' + "Ello"; // ensure it's a different reference
if (x.Equals(y)) { // also evaluates to TRUE
Ça sent vraiment. Lorsque vous surchargez ==
, Vous devez vous assurer que Equals()
et GetHashCode()
sont également cohérents. Voir directives MSDN .
Et la seule raison pour laquelle cela semble OK, c'est que vous décrivez votre type comme immuable.
Pour les types immuables, je ne pense pas qu'il y ait quelque chose de mal à avoir ==
Surchargé pour prendre en charge l'égalité des valeurs. Je ne pense pas que je remplacerais ==
Sans remplacer Equals
pour avoir la même sémantique cependant. Si vous remplacez ==
Et devez vérifier l'égalité de référence pour une raison quelconque, vous pouvez utiliser Object.ReferenceEquals(a,b)
.
Exemple montrant comment implémenter cela selon directives MSFT (ci-dessous). Notez que lorsque vous remplacez Equals, vous devez également remplacer GetHashCode (). J'espère que cela aide les gens.
public class Person
{
public Guid Id { get; private set; }
public Person(Guid id)
{
Id = id;
}
public Person()
{
Id = System.Guid.NewGuid();
}
public static bool operator ==(Person p1, Person p2)
{
bool rc;
if (System.Object.ReferenceEquals(p1, p2))
{
rc = true;
}
else if (((object)p1 == null) || ((object)p2 == null))
{
rc = false;
}
else
{
rc = (p1.Id.CompareTo(p2.Id) == 0);
}
return rc;
}
public static bool operator !=(Person p1, Person p2)
{
return !(p1 == p2);
}
public override bool Equals(object obj)
{
bool rc = false;
if (obj is Person)
{
Person p2 = obj as Person;
rc = (this == p2);
}
return rc;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Selon les meilleures pratiques de Microsofts, le résultat de la méthode Equals et la surcharge égal (==) devraient être les mêmes.
CA2224: Remplacer est égal à l'opérateur de surcharge est égal à