358 Stimmen

Warum müssen wir in C# sowohl == als auch != definieren?

Der C#-Compiler verlangt, dass immer dann, wenn ein benutzerdefinierter Typ den Operator == muss sie auch definieren != (siehe hier ).

Warum?

Ich bin neugierig, warum die Entwickler dies für notwendig hielten und warum der Compiler nicht auf eine vernünftige Implementierung für einen der beiden Operatoren zurückgreifen kann, wenn nur der andere vorhanden ist. In Lua kann man zum Beispiel nur den Gleichheitsoperator definieren und bekommt den anderen umsonst. C# könnte dasselbe tun, indem es Sie auffordert, entweder == oder sowohl == als auch != zu definieren, und dann den fehlenden !=-Operator automatisch kompiliert als !(left == right) .

Ich verstehe, dass es seltsame Eckfälle gibt, in denen einige Einheiten weder gleich noch ungleich sein können (wie IEEE-754 NaN's), aber diese scheinen die Ausnahme zu sein, nicht die Regel. Das erklärt also nicht, warum die Entwickler des C#-Compilers die Ausnahme zur Regel gemacht haben.

Ich habe Fälle gesehen, in denen der Gleichheitsoperator definiert wurde und der Ungleichheitsoperator ein Copy-Paste ist, bei dem jeder einzelne Vergleich umgekehrt und jedes && in einen || umgewandelt wurde (Sie verstehen schon... im Grunde !(a==b) erweitert durch De Morgans Regeln). Das ist eine schlechte Praxis, die der Compiler durch Design eliminieren könnte, wie es bei Lua der Fall ist.

Anmerkung: Das Gleiche gilt für die Operatoren < > <= >=. Ich kann mir keine Fälle vorstellen, in denen man diese auf unnatürliche Weise definieren muss. Lua lässt Sie nur < und <= definieren und definiert >= und > auf natürliche Weise durch die Negation der Formers. Warum tut C# nicht dasselbe (zumindest "standardmäßig")?

EDIT

Offensichtlich gibt es triftige Gründe dafür, dem Programmierer zu erlauben, Prüfungen auf Gleichheit und Ungleichheit nach Belieben zu implementieren. Einige der Antworten weisen auf Fälle hin, in denen das gut sein könnte.

Der Kern meiner Frage ist jedoch, warum dies zwangsweise in C# erforderlich ist, wenn in der Regel es ist nicht logischerweise notwendig?

Es steht auch in auffälligem Kontrast zu den Designentscheidungen für .NET-Schnittstellen wie Object.Equals , IEquatable.Equals IEqualityComparer.Equals wo das Fehlen eines NotEquals Gegenstück zeigt, dass der Rahmen Folgendes berücksichtigt !Equals() Objekte als ungleich und das war's. Außerdem werden Klassen wie Dictionary und Methoden wie .Contains() hängen ausschließlich von den vorgenannten Schnittstellen ab und verwenden die Operatoren nicht direkt, auch wenn sie definiert sind. In der Tat, wenn ReSharper Gleichheitsmitglieder erzeugt, definiert es sowohl == y != in Bezug auf Equals() und selbst dann nur, wenn der Benutzer beschließt, überhaupt Operatoren zu erzeugen. Die Gleichheitsoperatoren werden vom Framework nicht benötigt, um Objektgleichheit zu verstehen.

Im Grunde genommen kümmert sich das .NET-Framework nicht um diese Operatoren, es kümmert sich nur um ein paar Equals Methoden. Die Entscheidung, dass die Operatoren == und != vom Benutzer gemeinsam definiert werden müssen, hat rein mit dem Sprachdesign zu tun und nicht mit der Objektsemantik, soweit es .NET betrifft.

28 Stimmen

+1 für eine ausgezeichnete Frage. Es scheint überhaupt keinen Grund zu geben... natürlich könnte der Compiler davon ausgehen, dass a != b in !(a == b) übersetzt werden kann, solange ihm nichts anderes gesagt wird. Ich bin auch neugierig, warum man sich dazu entschlossen hat, dies zu tun.

0 Stimmen

Wenn es so einfach ist wie !(left == right) dann ist das kein Problem für Sie. Wenn die Negation viel komplizierter ist, hat der Compiler keine Chance zu optimieren - aber Sie. Daher ist es nur konsequent, Sie zu zwingen, beide Fälle selbst zu behandeln.

3 Stimmen

Die goldene Regel Nr. 1 bei der Entwicklung von Software, APIs und GUIs lautet: Machen Sie immer den Normalfall zum Standard! Es sieht so aus, als hätte das jemand versehentlich nicht getan.

3voto

Josh Punkte 438

Programmiersprachen sind syntaktische Umformungen besonders komplexer logischer Aussagen. Kann man in diesem Sinne einen Fall von Gleichheit definieren, ohne einen Fall von Nicht-Gleichheit zu definieren? Die Antwort lautet nein. Damit ein Objekt a gleich einem Objekt b ist, muss auch die Umkehrung von Objekt a ist nicht gleich b wahr sein. Eine andere Möglichkeit, dies zu zeigen, ist

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

Damit ist die Sprache definitiv in der Lage, die Gleichheit von Objekten zu bestimmen. Zum Beispiel kann der Vergleich NULL != NULL die Definition eines Gleichheitssystems, das keine Nicht-Gleichheitsanweisung implementiert, durcheinanderbringen.

Was nun die Idee betrifft, dass != einfach eine ersetzbare Definition ist, wie in

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

Dem kann ich nicht widersprechen. Es war jedoch höchstwahrscheinlich eine Entscheidung der C#-Sprachspezifikationsgruppe, dass der Programmierer gezwungen ist, die Gleichheit und Ungleichheit eines Objekts explizit gemeinsam zu definieren

0 Stimmen

Null wäre nur deshalb ein Problem, weil null ist eine gültige Eingabe für == was nicht der Fall sein sollte, obwohl es natürlich sehr praktisch ist. Ich persönlich bin der Meinung, dass es eine Menge vager, schlampiger Programmierung ermöglicht.

2voto

Emoire Punkte 29

Kurzum, erzwungene Konsequenz.

'==' und '!=' sind immer wahre Gegensätze, egal wie man sie definiert, da sie durch ihre verbale Definition von "gleich" und "nicht gleich" als solche definiert sind. Wenn man nur einen von beiden definiert, kann es zu einer Inkonsistenz des Gleichheitsoperators kommen, bei der sowohl '==' als auch '!=' für zwei gegebene Werte sowohl wahr als auch falsch sein können. Sie müssen beide definieren, denn wenn Sie sich für einen der beiden Operatoren entscheiden, müssen Sie auch den anderen entsprechend definieren, damit eindeutig klar ist, was Ihre Definition von "Gleichheit" ist. Die andere Lösung für den Compiler besteht darin, nur das Überschreiben von '==' ODER '!=' zuzulassen und das andere als inhärent negierend zu belassen. Offensichtlich ist das beim C#-Compiler nicht der Fall, und ich bin mir sicher, dass es dafür einen triftigen Grund gibt, der ausschließlich der Einfachheit halber gewählt werden kann.

Die Frage, die Sie sich stellen sollten, lautet: "Warum muss ich die Operatoren außer Kraft setzen?" Das ist eine schwerwiegende Entscheidung, die eine überzeugende Argumentation erfordert. Bei Objekten werden '==' und '!=' durch eine Referenz verglichen. Wenn Sie sie überschreiben, um NICHT per Referenz zu vergleichen, schaffen Sie eine allgemeine Inkonsistenz der Operatoren, die für andere Entwickler, die sich den Code ansehen, nicht erkennbar ist. Wenn Sie versuchen, die Frage "Ist der Zustand dieser beiden Instanzen gleichwertig?" zu stellen, dann sollten Sie IEquatible implementieren, Equals() definieren und diesen Methodenaufruf verwenden.

Schließlich definiert IEquatable() NotEquals() aus demselben Grund nicht: Es besteht die Gefahr, dass der Gleichheitsoperator inkonsistent wird. NotEquals() sollte IMMER !Equals() zurückgeben. Indem Sie die Definition von NotEquals() der Klasse überlassen, die Equals() implementiert, erzwingen Sie erneut die Frage der Konsistenz bei der Bestimmung der Gleichheit.

Edit: Das ist einfach meine Argumentation.

0 Stimmen

Das ist unlogisch. Wenn der Grund die Konsistenz wäre, würde das Gegenteil gelten: Sie könnten nur operator == und der Compiler würde daraus schließen operator != . Schließlich ist es das, was sie tut für operator + y operator += .

2 Stimmen

Foo += bar; ist eine zusammengesetzte Zuweisung, eine Kurzform für foo = foo + bar;. Es handelt sich nicht um einen Operator.

1 Stimmen

Wenn sie tatsächlich sind 'immer wahre Gegensätze', dann wäre das ein Grund a automatisch definieren a != b als !(a == b) (was bei C# nicht der Fall ist).

-3voto

Rhyous Punkte 6116

Wahrscheinlich haben sie einfach nicht daran gedacht, weil sie keine Zeit hatten, es zu tun.

Ich verwende Ihre Methode immer, wenn ich überladen bin == Dann verwende ich sie einfach in der anderen.

Sie haben Recht, mit ein wenig Arbeit könnte der Compiler uns dies kostenlos zur Verfügung stellen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X