7
votes

Objet.equals: tout est égal par défaut

En lisant Jeffrey Richter's CLR via C # 4ème édition (Microsoft Press) , l'auteur à un point indique que, tandis que objet.equals vérifie actuellement l'égalité d'identité, Microsoft aurait dû mettre en œuvre la méthode comme celle-ci : xxx

Cela me frappe comme très impair: tous les L'objet non nul du même type serait égal par défaut? Donc, à moins que la nervation: tous les instances d'un type sont égales (par exemple, tous vos objets de verrouillage sont égaux) et renvoyez le même code de hachage. Et en supposant que le == sur objet vérifie toujours l'égalité de référence, cela signifierait que (A == B)! = A. / B) qui serait aussi étrange.

Je pense que l'idée de choses étant égale si c'est exactement la même chose (identité) est une meilleure idée que de rendre tout simplement égal à moins que possible. Mais il s'agit d'une 4ème édition du livre bien connu publiée par Microsoft, il doit donc y avoir du mérite à cette idée. J'ai lu le reste du texte mais je ne pouvais pas m'empêcher de me demander: pourquoi l'auteur le suggère-t-il? Qu'est-ce que j'oublie ici? Quel est le grand avantage de la mise en œuvre de Richter sur l'objet actuel. Mise en œuvre?


2 commentaires

Bien que sa mise en œuvre ne soit pas claire, le commentaire explique correctement? Les objets sont égaux que si les champs correspondent.


+1 pour une question fantastique. J'ai lu le livre et honnêtement, je n'ai pas non plus vu l'avantage de la mettre en œuvre de cette façon.


4 Réponses :


5
votes

Le courant est égal () fait ce que l'on appelle un comparateur peu profond (ou un comparateur de référence), puis ne vérifie plus si les références diffèrent.

Je pense que cela est parfaitement acceptable pour une implémentation de base . Je ne penserais certainement pas que c'est faux ou incomplet.

Exemple de Richter 1 que vous citez est également parfaitement légitime pour le système de base.Object . La question avec sa mise en œuvre est qu'il faut sans doute être déclarée abstraite 2 - avec sa méthode, vous vous retrouverez avec un peu fiable () sur des objets dérivés si vous ne remplacez pas si vous ne remplacez pas Il (parce que égale () est censé faire un comparateur profond). Avoir à remplacer cette méthode sur tous les objets dérivés serait beaucoup de travail, la manière Microsoft est donc meilleure comme défaut . Donc, dans Essense, vous êtes correct: l'exemple de Richter est étrange - il est préférable de ne pas être par défaut de ne pas égal plutôt que l'inverse (par défaut de true entraînerait un comportement assez intéressant si les gens ont oublié de le remplacer. ).

(juste pour une référence facile, voici la mise en œuvre par défaut telle que publiée dans le livre)

Entrez la description de l'image ici



1: Richter est un homme intelligent qui connaît ses trucs et je ne discuterais pas généralement avec quoi que ce soit, il dit. Vous devez comprendre que les ingénieurs de la SP auraient dû réfléchir longuement et dur de beaucoup de choses, sachant qu'ils n'avaient pas la flexibilité de la possibilité de se tromper, puis de fixer des choses plus tard. Peu importe la raison, les gens vont toujours les deviner à une date ultérieure et proposera des opinions alternatives. Cela ne signifie pas que l'original est faux ou l'alternative est fausse - cela signifie simplement qu'il y avait une alternative.

2: Bien sûr signifie qu'il n'y aurait pas de mise en œuvre de base, ce qui serait bon car il aurait été peu fiable.


0 commentaires

3
votes

Jeffery Richter parle de valeur égalité sur identité égalité.

Spécifiquement, vous demandez:

Donc, à moins de remplacement: toutes les instances d'un type sont égales?

La réponse est oui , mais ... comme dans, oui, mais c'est (presque ) toujours censé être remplacé.

Ainsi, pour la plupart des classes, il devrait être remplacé par une comparaison d'attributs par attribut pour déterminer l'égalité. Pour d'autres classes qui sont vraiment basées sur l'identité (comme des verrous), il devrait être remplacé pour utiliser la même technique que celle utilisée aujourd'hui.

La clé est que cela doit être remplacé dans presque tous les cas, et cela seul est suffisamment difficile, maladroit et erroné - sujette que c'est probablement pourquoi Microsoft n'a pas utilisé cette approche.


Quel est l'avantage de la valeur-égalité sur l'égalité des identités? C'est que si deux objets différents ont les mêmes valeurs / contenus, ils peuvent être considérés comme «égaux» à des fins de comparaison dans des cas tels que les clés d'un objet dictionnaire.

ou considérez la matière des chaînes dans .NET, qui sont en fait des objets, mais sont traités beaucoup comme des valeurs à des niveaux plus élevés (en particulier dans VB.NET). Cela pose un problème lorsque vous souhaitez comparer deux chaînes pour l'égalité, car 99% du temps que vous ne vous souciez pas vraiment si ce sont des objets différents les instances , vous ne vous souciez que si elles contiennent le même texte. SO .NET doit s'assurer que c'est la manière dont la comparaison des chaînes fonctionne réellement, même si elles sont vraiment des objets.


3 commentaires

En fait, je voulais dire: Quel est le grand avantage de la mise en œuvre de Richter sur l'objet actuel. Mise en œuvre?


@VirtLink L'avantage est que cela explique efficacement les forces les personnes à remplacer est égal à afin d'obtenir une égalité qui signifie quelque chose, au lieu d'avoir une implémentation par défaut qui est rarement souhaitée, mais apparaît sembler approprié comme pour les nouveaux programmeurs. Cela revient à ce que les objets nécessitent très rarement une égalité de référence et souhaitent presque toujours utiliser l'égalité de valeur, mais la mise en œuvre par défaut est l'égalité de référence.


Surtout que la plupart des langues ont un autre opérateur / méthode spécifiquement pour l'égalité de référence / identité, comme est .



0
votes

devinez: le comportement actuel de objet.equals n'est pas ce que la plupart des gens considèrent comme "égaux".

Le motif principal (seulement?) de cette méthode d'exister est de permettre la recherche d'éléments dans les collections en prétendant être "==" Mise en œuvre. Donc, dans la plupart des cas pratiques, cette mise en œuvre se comporte de manière inattendue (à l'exception de l'affaire lorsque vous souhaitez trouver si une instance particulière est déjà dans la collection) et vous forcez à vous fournir des fonctions de comparaison personnalisées ...

probablement c'est une méthode d'objet parce que pour des raisons techniques. C'est à dire. Pour le tableau / dictionnaire, il peut être plus rapide d'assumer que tous les objets ont égal / gethash au lieu de vérifier quelque chose sur l'objet pour activer la fonctionnalité "Rechercher".

sans doute, il ne doit pas être sur un objet du tout et nécessitera simplement des classes pouvant être stockées dans des collections pour mettre en œuvre une partie de l'interface icomparable .


1 commentaires

Vous voulez dire iequaltable pas icomparable . De nombreux objets peuvent être égaux ou non égaux sans pouvoir déterminer lequel est plus grand ou moins que l'autre.



1
votes

Si on est invitée à faire une liste de tous des objets d'arbitraires identifiablement distincts, et n'a aucune indication de ce que les objets sont ou ce qu'ils seront utilisés, seuls les moyens universellement applicables de tester si deux Les références doivent être considérées comme indiquant que les objets identifiablement distincts sont objet.equaux (objet) . Deux références x et y doivent être considérées comme identifiables-distinctes si elles sont modifiées une ou plusieurs références qui pointent actuellement sur x de sorte qu'ils pointent sur < Code> y serait probablement modifier le comportement du programme.

Par exemple, si deux instances de String contiennent tous les deux tout le texte de guerre et paix , ponctués et formatés de manière identique, on pourrait probablement remplacer certaines ou toutes les références à la d'abord avec des références à la seconde, ou vice versa, avec peu ou aucun effet sur l'exécution du programme au-delà du fait qu'une comparaison entre deux références qui pointent sur la même instance peut être trouvée beaucoup plus rapidement que deux références qui ne peuvent pas faire deux références qui pointent. à différentes chaînes contenant des caractères identiques.

Dans la plupart des cas, des objets qui existent pour contenir des données immuables doivent être considérés comme identiques si les données qu'ils détiennent sont identiques. Les objets qui existent pour contenir des données mutables ou qui existent pour servir de jetons d'identité doivent généralement être considérés comme distincts les uns des autres. Étant donné que l'on peut définir un égalleur sur mesure qui considère comme des objets équivalents qui ne sont pas totalement équivalents (par exemple, un comparateur de chaîne insensible à une casse), et étant donné que le code nécessitant une certaine définition de l'équivalence plus large que une équivalence stricte devrait généralement savoir quels types il travaille avec et quelle définition de l'équivalence est appropriée, il est généralement préférable d'avoir objet.equals signaler des objets comme étant différent à moins qu'ils soient conçus pour être substituables (comme cela être, par exemple, des cordes).

Pour utiliser une analogie du monde réel, supposons que l'on reçoive deux morceaux de papier, chacun avec un numéro d'identification de véhicule écrit dessus et est demandé si la voiture identifiée par le premier morceau de papier est identique à la voiture identifiée. par la seconde. Si les deux glissades de papier ont le même Vin, il est clair que la voiture identifiée par la première est la même que celle identifiée par la seconde. S'ils ont des Vins différents, cependant, à l'exclusion de toute possibilité étrange d'une voiture ayant plus d'un VIN, puis identifient différentes voitures. Même si les voitures ont la même marque et le même modèle, les packages d'options, le schéma de peinture, etc. Ils seraient toujours différentes voitures. Une personne qui a acheté on ne serait pas autorisée à commencer arbitrairement à l'aide de l'autre. Il peut parfois être utile de savoir si deux voitures ont actuellement les mêmes packages d'options, etc. Mais si c'est ce que l'on veut savoir, c'est ce que l'on devrait demander.


6 commentaires

Donc, si je vous comprends correctement: Sauf si il est logique que l'objet de l'objet de remplacer est égal à pour effectuer une vérification de l'égalité de valeur, vous acceptez que l'objet par défaut devrait ne pas retourner true mais que l'égalité de référence vérifie-t-elle actuellement.


@VirtLink: précisément. Une faiblesse en Java, qui transporte en grande partie à .NET, est qu'il n'y a pas de distinction entre les références d'objet qui sont conservées pour encapsuler l'identité de leur cible, ce qui encapsule contentement mutable Celui-ci encapsule et qui encapsule ni [encapsulant juste du contenu immuable, autre que l'identité]. Le type de base objet n'a aucun contenu - tout ce qu'il a une identité, c'est donc la seule base sensible à la comparaison. D'autres types tels que chaîne ont un contenu immuable, mais aucune identité forte.


@VirtLink: Les objets de types mutables ont généralement une identité forte, sauf indication non (1) qu'il n'existe qu'une référence persistante (autre qu'une variable locale), n'importe où dans l'univers, ou (2) aucune référence ne sera jamais détenue par quelque chose qui va muté l'objet en question. Seulement si l'une de ces conditions s'applique au sens qu'il serait logique de considérer l'égalité de valeur plutôt que de l'égalité de référence, et il n'y a aucun moyen qu'un type de classe puisse savoir que l'un d'entre eux s'applique. Notez cependant que le n ° 1 s'applique aux types de valeur non complets et s'applique généralement aux types de valeur en boîte.


Bien que l'identité puisse fonctionner par défaut, la comparaison sur l'égalité par défaut n'est apparemment pas très significative. Certains parlent même de faire égale résumé. J'irais même aussi loin que d'indiquer que objet ne doit pas avoir de égale ou un gethashcode . Les deux devraient être dans Iequatable . Toute classe doit spécifier l'égalité personnalisée qui s'applique à celui-ci en implémentant Iequatable et que seul un comparateur d'égalité personnalisé peut être utilisé pour comparer des objets (par exemple un RéférencesAsalityComParer ). EDIT: HMM .. Apparemment Jon Skeet pense aussi.


@VirtLink: Iequatable est cassé en ce qui concerne les types héritables. En outre, je ne sais pas pourquoi vous pensez que la comparaison sur l'égalité par défaut n'est pas significative. Si des objets implémentent égale tel que x.equals (y) implique x est substituable pour y , alors c'est possible. Pour rédiger un interne générique faimérer cache pour accélérer les choses telles que la désérialisation (si une instance nouvellement déséréalisée correspond à une performance préexistante, des performances peuvent être améliorées en supprimant le nouveau et en utilisant l'ancien à la place). Le fait que certains types de cadre ...


... Définir est égal à pour signifier quelque chose que l'équivalence sémantique complique un peu les choses, mais cela ne signifie pas qu'une méthode universellement disponible pour tester si deux références sont équivalentes ne serait pas significative.