Pourquoi devons-nous définir à la fois == et! = En C #?

346

Le compilateur C # requiert que chaque fois qu'un type personnalisé définit un opérateur ==, il doit également définir !=(voir ici ).

Pourquoi?

Je suis curieux de savoir pourquoi les concepteurs l'ont jugé nécessaire et pourquoi le compilateur ne peut-il pas adopter par défaut une implémentation raisonnable pour l'un ou l'autre des opérateurs alors que seul l'autre est présent. Par exemple, Lua vous permet de définir uniquement l'opérateur d'égalité et vous obtenez l'autre gratuitement. C # pourrait faire de même en vous demandant de définir soit == soit les deux == et! =, Puis de compiler automatiquement l'opérateur! = Manquant en tant que !(left == right).

Je comprends qu'il y a des cas étranges où certaines entités peuvent ne pas être égales ou inégales (comme IEEE-754 NaN), mais celles-ci semblent être l'exception, pas la règle. Cela n'explique donc pas pourquoi les concepteurs du compilateur C # ont fait de l'exception la règle.

J'ai vu des cas de mauvaise exécution où l'opérateur d'égalité est défini, puis l'opérateur d'inégalité est un copier-coller avec chaque comparaison inversée et chaque && basculé vers un || (vous obtenez le point ... en gros! (a == b) développé par les règles de De Morgan). C'est une mauvaise pratique que le compilateur pourrait éliminer par conception, comme c'est le cas avec Lua.

Remarque: Il en va de même pour les opérateurs <> <=> =. Je ne peux pas imaginer des cas où vous aurez besoin de les définir de manière non naturelle. Lua vous permet de définir uniquement <et <= et définit> = et> naturellement à travers la négation des formateurs. Pourquoi C # ne fait-il pas de même (au moins «par défaut»)?

ÉDITER

Apparemment, il existe des raisons valables pour permettre au programmeur de mettre en œuvre des contrôles d'égalité et d'inégalité comme bon lui semble. Certaines réponses indiquent des cas où cela peut être bien.

Le noyau de ma question, cependant, est pourquoi cela est requis de force en C # alors que ce n'est généralement pas nécessaire logiquement ?

C'est également en contraste frappant avec les choix de conception pour les interfaces .NET comme Object.Equals, IEquatable.Equals IEqualityComparer.Equalsoù l'absence d'un NotEqualshomologue montre que le cadre considère les !Equals()objets comme inégaux et c'est tout. De plus, les classes comme Dictionaryet les méthodes comme .Contains()dépendent exclusivement des interfaces susmentionnées et n'utilisent pas directement les opérateurs même s'ils sont définis. En fait, lorsque ReSharper génère des membres d'égalité, il définit à la fois ==et !=en termes de Equals()et même alors seulement si l'utilisateur choisit de générer des opérateurs. Les opérateurs d'égalité ne sont pas nécessaires au framework pour comprendre l'égalité des objets.

Fondamentalement, le framework .NET ne se soucie pas de ces opérateurs, il ne se soucie que de quelques Equalsméthodes. La décision d'exiger que les opérateurs == et! = Soient définis en tandem par l'utilisateur est uniquement liée à la conception du langage et non à la sémantique des objets en ce qui concerne .NET.

Stefan Dragnev
la source
24
+1 pour une excellente question. Il ne semble pas y avoir de raison du tout ... bien sûr, le compilateur pourrait supposer que a! = B peut être traduit en! (A == b) sauf indication contraire. Je suis curieux de savoir pourquoi ils ont décidé de faire cela aussi.
Patrick87
16
C'est le plus rapide que j'ai vu une question votée et favorisée.
Christopher Currens
26
Je suis sûr que @Eric Lippert peut également fournir une bonne réponse.
Beurk
17
"Le scientifique n'est pas celui qui donne les bonnes réponses, c'est celui qui pose les bonnes questions". C'est pourquoi en SE, les questions sont encouragées. Et il fonctionne!
Adriano Carneiro
4
La même question pour Python: stackoverflow.com/questions/4969629/…
Josh Lee

Réponses:

161

Je ne peux pas parler pour les concepteurs de langage, mais d'après ce que je peux raisonner, il semble que c'était une décision de conception intentionnelle et appropriée.

En regardant ce code F # de base, vous pouvez le compiler dans une bibliothèque de travail. C'est un code légal pour F #, et ne surcharge que l'opérateur d'égalité, pas l'inégalité:

module Module1

type Foo() =
    let mutable myInternalValue = 0
    member this.Prop
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

    static member op_Equality (left : Foo, right : Foo) = left.Prop = right.Prop
    //static member op_Inequality (left : Foo, right : Foo) = left.Prop <> right.Prop

Cela fait exactement à quoi il ressemble. Il crée un comparateur d'égalité ==uniquement et vérifie si les valeurs internes de la classe sont égales.

Bien que vous ne puissiez pas créer une classe comme celle-ci en C #, vous pouvez en utiliser une qui a été compilée pour .NET. Il est évident qu'il utilisera notre opérateur surchargé pour == Alors, à quoi sert le runtime !=?

La norme C # EMCA contient tout un tas de règles (section 14.9) expliquant comment déterminer quel opérateur utiliser lors de l'évaluation de l'égalité. Pour le dire trop simplifié et donc pas parfaitement précis, si les types qui sont comparés sont du même type et qu'un opérateur d'égalité surchargé est présent, il utilisera cette surcharge et non l'opérateur d'égalité de référence standard hérité d'Object. Il n'est donc pas surprenant que si un seul des opérateurs est présent, il utilisera l'opérateur d'égalité de référence par défaut, que tous les objets ont, il n'y a pas de surcharge pour lui. 1

Sachant que c'est le cas, la vraie question est: pourquoi a-t-il été conçu de cette manière et pourquoi le compilateur ne le comprend-il pas tout seul? Beaucoup de gens disent que ce n'était pas une décision de conception, mais j'aime à penser que cela a été pensé de cette façon, en particulier en ce qui concerne le fait que tous les objets ont un opérateur d'égalité par défaut.

Alors, pourquoi le compilateur ne crée-t-il pas automatiquement l' !=opérateur? Je ne peux pas être sûr à moins que quelqu'un de Microsoft ne le confirme, mais c'est ce que je peux déterminer en raisonnant sur les faits.


Pour éviter un comportement inattendu

Peut-être que je veux faire une comparaison de valeurs ==pour tester l'égalité. Cependant, en ce qui concerne, !=je ne me soucie pas du tout si les valeurs sont égales à moins que la référence soit égale, car pour que mon programme les considère comme égales, je ne me soucie que si les références correspondent. Après tout, cela est en fait décrit comme le comportement par défaut du C # (si les deux opérateurs n'étaient pas surchargés, comme ce serait le cas pour certaines bibliothèques .net écrites dans une autre langue). Si le compilateur ajoutait du code automatiquement, je ne pouvais plus compter sur le compilateur pour produire du code qui devrait être conforme. Le compilateur ne doit pas écrire de code caché qui modifie le comportement du vôtre, en particulier lorsque le code que vous avez écrit respecte les normes de C # et de CLI.

En ce qui vous oblige à le surcharger, au lieu d'aller au comportement par défaut, je peux seulement dire fermement qu'il est dans la norme (EMCA-334 17.9.2) 2 . La norme ne précise pas pourquoi. Je crois que cela est dû au fait que C # emprunte beaucoup de comportement à C ++. Voir ci-dessous pour en savoir plus.


Lorsque vous remplacez !=et ==, vous n'avez pas à renvoyer bool.

C'est une autre raison probable. En C #, cette fonction:

public static int operator ==(MyClass a, MyClass b) { return 0; }

est aussi valide que celui-ci:

public static bool operator ==(MyClass a, MyClass b) { return true; }

Si vous retournez autre chose que bool, le compilateur ne peut pas déduire automatiquement un type opposé. En outre, dans le cas où votre opérateur ne bool retour, il n'a tout simplement pas de sens pour eux de créer de générer un code qui existerait seulement dans ce un cas spécifique ou, comme je l' ai dit plus haut, le code qui cache le comportement par défaut du CLR.


C # emprunte beaucoup au C ++ 3

Lorsque C # a été introduit, il y avait un article dans le magazine MSDN qui écrivait, parlant de C #:

De nombreux développeurs souhaitent qu'il existe un langage facile à écrire, à lire et à entretenir comme Visual Basic, mais qui offre toujours la puissance et la flexibilité de C ++.

Oui, l'objectif de conception pour C # était de donner presque la même quantité de puissance que C ++, en ne sacrifiant qu'un peu pour des commodités telles que la sécurité de type rigide et la collecte des ordures. C # a été fortement modélisé après C ++.

Vous ne serez peut-être pas surpris d'apprendre qu'en C ++, les opérateurs d'égalité n'ont pas à renvoyer bool , comme le montre cet exemple de programme

Maintenant, C ++ ne vous oblige pas directement à surcharger l'opérateur complémentaire. Si vous avez compilé le code dans l'exemple de programme, vous verrez qu'il s'exécute sans erreur. Cependant, si vous avez essayé d'ajouter la ligne:

cout << (a != b);

tu auras

erreur du compilateur C2678 (MSVC): binaire '! =': aucun opérateur trouvé qui prend un opérande de gauche de type 'Test' (ou il n'y a pas de conversion acceptable) '.

Ainsi, bien que C ++ lui-même ne vous oblige pas à surcharger par paires, il ne vous permettra pas d'utiliser un opérateur d'égalité que vous n'avez pas surchargé sur une classe personnalisée. Il est valide dans .NET, car tous les objets en ont un par défaut; C ++ ne fonctionne pas.


1. En remarque, la norme C # vous oblige toujours à surcharger la paire d'opérateurs si vous voulez surcharger l'un ou l'autre. Ceci fait partie de la norme et pas simplement du compilateur . Cependant, les mêmes règles concernant la détermination de l'opérateur à appeler s'appliquent lorsque vous accédez à une bibliothèque .net écrite dans une autre langue qui n'a pas les mêmes exigences.

2. EMCA-334 (pdf) ( http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf )

3. Et Java, mais ce n'est vraiment pas le point ici

Christopher Currens
la source
75
" vous n'avez pas à retourner bool " .. Je pense que c'est notre réponse juste là; bien joué. Si! (O1 == o2) n'est même pas bien défini, alors vous ne pouvez pas vous attendre à ce que la norme s'y fie.
Brian Gordon
10
Ironiquement, dans une rubrique sur les opérateurs logiques, vous avez utilisé un double négatif dans la phrase, "C # ne vous permet pas de ne remplacer qu'un seul des deux", ce qui signifie en réalité "C # ne vous permet de remplacer qu'un seul des deux".
Dan Diplo
13
@Dan Diplo, ça va, ce n'est pas comme si je n'étais pas interdit de ne pas faire ça ou pas.
Christopher Currens
6
Si c'est vrai, je soupçonne que # 2 est correct; mais maintenant la question devient, pourquoi permettre ==de retourner autre chose qu'un bool? Si vous retournez un int, vous ne pouvez plus l'utiliser comme instruction conditionnelle, par exemple. if(a == b)ne compilera plus. À quoi ça sert?
BlueRaja - Danny Pflughoeft
2
Vous pouvez renvoyer un objet qui a une conversion implicite en bool (opérateur vrai / faux) mais je n'arrive toujours pas à voir où cela serait utile.
Stefan Dragnev
53

Probablement si quelqu'un a besoin d'implémenter une logique à trois valeurs (c. null-à-d.). Dans des cas comme celui-ci - SQL standard ANSI, par exemple - les opérateurs ne peuvent pas simplement être annulés en fonction de l'entrée.

Vous pourriez avoir un cas où:

var a = SomeObject();

Et a == truerevient falseet a == falserevient également false.

Beurk
la source
1
Je dirais que dans ce cas, puisque ce an'est pas un booléen, vous devriez le comparer avec une énumération à trois états, pas un réel trueou false.
Brian Gordon
18
Au fait, je ne peux pas croire que personne n'ait référencé la blague FileNotFound ..
Brian Gordon
28
Si a == truec'est le cas, falseje m'attendrais toujours a != trueà l'être true, malgré le a == falsefaitfalse
Fede
20
@Fede a frappé le clou sur la tête. Cela n'a vraiment rien à voir avec la question - vous expliquez pourquoi quelqu'un pourrait vouloir passer outre ==, pas pourquoi il devrait être forcé de passer outre les deux.
BlueRaja - Danny Pflughoeft
6
@Yuck - Oui, il existe une bonne implémentation par défaut: c'est le cas commun. Même dans votre exemple, l'implémentation par défaut de !=serait correcte. Dans le cas extrêmement rare où nous voudrions x == yet que x != yles deux soient faux (je ne peux pas penser à un seul exemple qui ait du sens) , ils pourraient toujours remplacer l'implémentation par défaut et fournir la leur. Toujours faire du cas commun la valeur par défaut!
BlueRaja - Danny Pflughoeft
25

À part cela, C # diffère en C ++ dans de nombreux domaines, la meilleure explication à laquelle je peux penser est que dans certains cas, vous voudrez peut-être prendre un peu approche différente pour prouver "pas l'égalité" que pour prouver "l'égalité".

Évidemment, avec la comparaison de chaînes, par exemple, vous pouvez simplement tester l'égalité et returnsortir de la boucle lorsque vous voyez des caractères qui ne correspondent pas. Cependant, il pourrait ne pas être aussi propre avec des problèmes plus compliqués. Le filtre de floraison me vient à l'esprit; il est très facile de dire rapidement si l'élément n'est pas dans l'ensemble, mais difficile de dire si l'élément est dans l'ensemble. Bien que la même returntechnique puisse s'appliquer, le code n'est peut-être pas aussi joli.

Brian Gordon
la source
6
Excellent exemple; Je pense que vous êtes sur la raison. Un simple !vous enferme dans une définition unique de l'égalité, où un codeur averti pourrait être en mesure d'optimiser les deux == et !=.
Beurk
13
Cela explique donc pourquoi ils devraient avoir la possibilité de remplacer les deux, et non pourquoi ils devraient être forcés de le faire.
BlueRaja - Danny Pflughoeft
1
Dans cette optique, ils n'ont pas à optimiser les deux, ils doivent simplement fournir une définition claire des deux.
Jesper
22

Si vous regardez les implémentations de surcharges de == et! = Dans la source .net, elles n'implémentent souvent pas! = Comme! (Gauche == droite). Ils l'implémentent complètement (comme ==) avec une logique négative. Par exemple, DateTime implémente == comme

return d1.InternalTicks == d2.InternalTicks;

et! = as

return d1.InternalTicks != d2.InternalTicks;

Si vous (ou le compilateur le faisait implicitement) deviez implémenter! = As

return !(d1==d2);

alors vous faites une hypothèse sur l'implémentation interne de == et! = dans les choses que votre classe référence. Éviter cette hypothèse peut être la philosophie derrière leur décision.

hache - fait avec SOverflow
la source
17

Pour répondre à votre modification, concernant la raison pour laquelle vous êtes obligé de remplacer les deux si vous en remplacez un, tout est dans l'héritage.

Si vous remplacez ==, le plus susceptible de fournir une sorte d'égalité sémantique ou structurelle (par exemple, DateTimes sont égaux si leurs propriétés InternalTicks sont égales même si elles peuvent être différentes instances), alors vous changez le comportement par défaut de l'opérateur de Object, qui est le parent de tous les objets .NET. L'opérateur == est, en C #, une méthode dont l'implémentation de base Object.operator (==) effectue une comparaison référentielle. Object.operator (! =) Est une autre méthode différente, qui effectue également une comparaison référentielle.

Dans presque tous les autres cas de substitution de méthode, il serait illogique de présumer que la substitution d'une méthode entraînerait également un changement de comportement vers une méthode antonymique. Si vous avez créé une classe avec les méthodes Increment () et Decrement () et que vous avez remplacé Increment () dans une classe enfant, vous attendriez-vous à ce que Decrement () soit également remplacé par le contraire de votre comportement substitué? Le compilateur ne peut pas être rendu suffisamment intelligent pour générer une fonction inverse pour toute implémentation d'un opérateur dans tous les cas possibles.

Cependant, les opérateurs, bien qu'implémentés de manière très similaire aux méthodes, fonctionnent conceptuellement par paires; == et! =, <et> et <= et> =. Il serait illogique dans ce cas du point de vue d'un consommateur de penser que! = Fonctionne différemment de ==. Donc, le compilateur ne peut pas supposer que a! = B ==! (A == b) dans tous les cas, mais on s'attend généralement à ce que == et! = Fonctionnent de la même manière, donc le compilateur force vous mettre en œuvre par paires, mais vous finissez par le faire. Si, pour votre classe, a! = B ==! (A == b), alors implémentez simplement l'opérateur! = En utilisant! (==), mais si cette règle ne s'applique pas dans tous les cas à votre objet (par exemple , si la comparaison avec une valeur particulière, égale ou inégale, n'est pas valide), alors vous devez être plus intelligent que l'IDE.

La VRAIE question à poser est pourquoi <et> et <= et> = sont des paires d'opérateurs comparatifs qui doivent être implémentées simultanément, quand en termes numériques! (A <b) == a> = b et! (A> b) == a <= b. Vous devriez être tenu de mettre en œuvre les quatre si vous en remplacez un, et vous devriez probablement aussi être obligé de remplacer == (et! =), Car (a <= b) == (a == b) si a est sémantiquement égal à b.

KeithS
la source
14

Si vous surchargez == pour votre type personnalisé, et non! = Alors il sera géré par l'opérateur! = Pour l'objet! = Objet car tout est dérivé de l'objet, et ce serait très différent de CustomType! = CustomType.

De plus, les créateurs de langage l'ont probablement voulu de cette façon pour permettre le plus de flexibilité possible aux codeurs, et aussi pour qu'ils ne fassent pas d'hypothèses sur ce que vous avez l'intention de faire.

Chris Mullins
la source
Vous avez inspiré cette question: stackoverflow.com/questions/6919259/…
Brian Gordon
2
La raison de la flexibilité peut également s'appliquer à de nombreuses fonctionnalités qu'ils ont décidé de laisser de côté, par exemple blogs.msdn.com/b/ericlippert/archive/2011/06/23/… .Ainsi, cela n'explique pas leur choix pour la mise en place d'opérateurs d'égalité.
Stefan Dragnev
C'est très intéressant. Il semble que ce serait une fonctionnalité utile. Je ne sais pas pourquoi ils l'auraient laissé de côté.
Chris Mullins
11

C'est ce qui me vient à l'esprit en premier:

  • Et si le test de l'inégalité est beaucoup plus rapide que le test de l'égalité?
  • Que se passe-t-il si dans certains cas vous souhaitez retourner à la falsefois pour ==et!= (c'est-à-dire s'ils ne peuvent pas être comparés pour une raison quelconque)
Dan Abramov
la source
5
Dans le premier cas, vous pouvez ensuite implémenter des tests d'égalité en termes de tests d'inégalité.
Stefan Dragnev
Le deuxième cas cassera des structures comme Dictionaryet Listsi vous utilisez votre type personnalisé avec elles.
Stefan Dragnev
2
@Stefan: Dictionaryutilise GetHashCodeet Equalsnon les opérateurs. Listutilise Equals.
Dan Abramov
6

Eh bien, c'est probablement juste un choix de conception, mais comme vous le dites, x!= yil ne doit pas nécessairement être le même que !(x == y). En n'ajoutant pas d'implémentation par défaut, vous êtes certain de ne pas oublier d'implémenter une implémentation spécifique. Et si c'est en effet aussi trivial que vous le dites, vous pouvez simplement implémenter l'un en utilisant l'autre. Je ne vois pas en quoi c'est une «mauvaise pratique».

Il peut également y avoir d'autres différences entre C # et Lua ...

GolezTrol
la source
1
C'est une excellente pratique de mettre en œuvre l'un en fonction de l'autre. Je viens de le voir faire autrement - ce qui est sujet aux erreurs.
Stefan Dragnev
3
C'est le problème du programmeur, pas le problème de C #. Les programmeurs qui ne parviennent pas à mettre en œuvre ce droit échoueront également dans d'autres domaines.
GolezTrol
@GolezTrol: Pourriez-vous expliquer cette référence Lua? Je ne connais pas du tout Lua, mais votre référence semble faire allusion à quelque chose.
zw324
@Ziyao Wei: OP souligne que Lua fait cela différemment de C # (Lua ajoute apparemment des homologues par défaut pour les opérateurs mentionnés). J'essaye juste de banaliser une telle comparaison. S'il n'y a aucune différence, alors au moins l'une d'entre elles n'a pas le droit d'exister. Je dois dire que je ne connais pas Lua non plus.
GolezTrol
6

Les mots clés de votre question sont « pourquoi » et « doit ».

Par conséquent:

Répondre de cette façon parce qu'ils l'ont conçu ainsi, c'est vrai ... mais ne pas répondre à la partie "pourquoi" de votre question.

Répondre qu'il peut parfois être utile de remplacer ces deux éléments indépendamment, est vrai ... mais ne pas répondre à la partie "incontournable" de votre question.

Je pense que la réponse simple est qu'il n'y a pas une raison convaincante pourquoi C # exige que vous de passer outre les deux.

La langue devrait vous permettre de passer outre que ==, et vous fournir une implémentation par défaut de !=c'est !que. Si vous souhaitez également remplacer, essayez-le !=.

Ce n'était pas une bonne décision. Les humains conçoivent des langages, les humains ne sont pas parfaits, C # n'est pas parfait. Haussement d'épaules et QED

Greg Hendershott
la source
5

Juste pour ajouter aux excellentes réponses ici:

Considérez ce qui se passerait dans le débogueur , lorsque vous essayez d'entrer dans un !=opérateur et de vous retrouver dans un== opérateur à la place! Parlez de confusion!

Il est logique que CLR vous permette de laisser de côté l'un ou l'autre des opérateurs - car il doit fonctionner avec de nombreuses langues. Mais il y a beaucoup d'exemples de C # ne pas exposer les caractéristiques CLR ( refretours et locaux, par exemple), et beaucoup d'exemples de mise en œuvre de fonctionnalités non dans le CLR lui - même (par exemple: using, lock, foreach, etc.).

Andrew Russell
la source
3

Les langages de programmation sont des réarrangements syntaxiques d'instructions logiques exceptionnellement complexes. Dans cet esprit, pouvez-vous définir un cas d'égalité sans définir un cas de non-égalité? La réponse est non. Pour qu'un objet a soit égal à l'objet b, alors l'inverse de l'objet a différent de b doit également être vrai. Une autre façon de le montrer est

if a == b then !(a != b)

cela permet au langage de déterminer l’égalité des objets. Par exemple, la comparaison NULL! = NULL peut jeter une clé dans la définition d'un système d'égalité qui n'implémente pas une déclaration de non-égalité.

Maintenant, en ce qui concerne l'idée de! = Étant simplement une définition remplaçable comme dans

if !(a==b) then a!=b

Je ne peux pas contester cela. Cependant, c'était probablement une décision du groupe de spécification du langage C # que le programmeur soit obligé de définir explicitement l'égalité et la non-égalité d'un objet ensemble

Josh
la source
Nullne serait un problème que parce qu'il nulls'agit d'une entrée valide ==, ce qui ne devrait pas être le cas, bien qu'évidemment, c'est extrêmement pratique. Personnellement, je pense simplement que cela permet de vastes quantités de programmation vague et bâclée.
nicodemus13
2

Bref, une cohérence forcée.

'==' et '! =' sont toujours de vrais opposés, quelle que soit la façon dont vous les définissez, définis comme tels par leur définition verbale de "égal" et "non égal". En ne définissant qu'un seul d'entre eux, vous vous ouvrez à une incohérence d'opérateur d'égalité où '==' et '! =' Peuvent tous les deux être vrais ou tous les deux faux pour deux valeurs données. Vous devez définir les deux, car lorsque vous choisissez d'en définir un, vous devez également définir l'autre de manière appropriée afin de clarifier clairement votre définition de «l'égalité». L'autre solution pour le compilateur est de vous autoriser uniquement à remplacer '==' OU '! =' Et à laisser l'autre comme négativement intrinsèque à l'autre. Évidemment, ce n'est pas le cas avec le compilateur C # et je suis sûr qu'il y a '

La question que vous devriez vous poser est "pourquoi dois-je remplacer les opérateurs?" C'est une décision forte à prendre qui nécessite un raisonnement fort. Pour les objets, '==' et '! =' Comparent par référence. Si vous devez les remplacer pour ne PAS comparer par référence, vous créez une incohérence d'opérateur générale qui n'est apparente à aucun autre développeur qui lirait ce code. Si vous essayez de poser la question «l'état de ces deux instances est-il équivalent?», Vous devez implémenter IEquatible, définir Equals () et utiliser cet appel de méthode.

Enfin, IEquatable () ne définit pas NotEquals () pour le même raisonnement: possibilité d'ouvrir des incohérences d'opérateur d'égalité. NotEquals () doit TOUJOURS retourner! Equals (). En ouvrant la définition de NotEquals () à la classe implémentant Equals (), vous forcez à nouveau la question de la cohérence dans la détermination de l'égalité.

Edit: C'est tout simplement mon raisonnement.

Emoire
la source
C'est illogique. Si la raison était la cohérence, alors l'inverse s'appliquerait: vous ne seriez en mesure de l'implémenter operator ==et le compilateur en déduirait operator !=. Après tout, c'est ce qu'il fait pour operator +et operator +=.
Konrad Rudolph
1
foo + = bar; est une affectation composée, raccourci pour foo = foo + bar ;. Ce n'est pas un opérateur.
blenderfreaky
En effet , si elles sont « toujours vrais opposés », alors ce serait une raison pour définir automatiquement a != bcomme !(a == b)... ( ce qui est pas ce que C # fait).
andrewf
-3

Probablement juste une chose à laquelle ils n'avaient pas pensé n'avait pas le temps de faire.

J'utilise toujours votre méthode lorsque je surcharge ==. Ensuite, je l'utilise simplement dans l'autre.

Vous avez raison, avec un peu de travail, le compilateur pourrait nous le donner gratuitement.

Rhyous
la source