Probleme mit überladenem operator ==
-
Stimmt, daran habe ich nicht gedacht. Aber hast du es schonmal mit Object.operator== oder base.operator== probiert? Dann würdest du dir den cast sparen (ich hasse casts).
Ist jetzt ungetestet, aber solltest du vielleicht mal kurz noch checken.
-
AndreasW schrieb:
Optimizer schrieb:
Und schau dir auch mal an, was ein Equals machen sollte:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)
Ist zwar Java, aber das hat C# eh von Java geklaut.das ist doch gewährleistet.
Sicher? Eine id zu vergleichen bedeutet für mich Referenzgleichheit. Dazu sollte man Equals() nicht verwenden, und man kann sich das überladen von == dann auch sparen.
Falls mehrere Objekte die selbe id haben können, bitte ich um Verzeihung.
-
Also, ich lese die CollisionMaterials aus einer Xml-Datei aus. Andere Objekte referenzieren ("benutzen") jeweils ein CollisionMaterial über dessen Id. In der Liste, welche die Materials speichert, möchte ich keine doppelten Objekte haben.
Aber Equals (und operatoren) zu überschreiben, ist doch gerade der Sinn des Ganzen. Wenn ich Objekte auf eine bestimmte Art und Weise vergleiche / identifiziere, kann das so gewährleisten.
Das ist doch das gleiche Prinzip, wie Javas Interface Comparable (mit der Methode public boolean CompareTo(Object o)), nur eleganter, weil ich in C# die Operatoren überladen kann und sie dann benutzen kann, wie bei ganz normalen. primitiven Datentypen bzw. String.
-
Nein, das hat mit Compareable nicht zu tun.
Equals() - Ob zwei (möglicherweise nicht die selben) Objekte den gleichen Zustand haben. Bsp.: Zwei verschiedene Brüche, die den selben Wert haben
=> logische GleichheitEquals ist nicht dafür gedacht, zu prüfen, ob zwei Objekte die selben sind. Dazu brauchst du sowieso nur die Referenz vergleichen, da kannst du dir den ganzen Aufwand sparen.
Weise vergleiche / identifiziere
Vergleichen ja, identifizieren nein!
Du kannst natürlich machen, was du willst. Aber deine Klasse möchte ich dann nicht im nächsten Framework haben.
-
edit: war egal
edit: oder vielelicht doch:Equals() - Ob zwei (möglicherweise nicht die selben) Objekte den gleichen Zustand haben. Bsp.: Zwei verschiedene Brüche, die den selben Wert haben
=> logische Gleichheitja. Beispiel aus der Hilfe:
using System; public class MyClass { public static void Main() { string s1 = "Tom"; string s2 = "Carol"; Console.WriteLine("Object.Equals(\"{0}\", \"{1}\") => {2}", s1, s2, Object.Equals(s1, s2)); s1 = "Tom"; s2 = "Tom"; Console.WriteLine("Object.Equals(\"{0}\", \"{1}\") => {2}", s1, s2, Object.Equals(s1, s2)); s1 = null; s2 = "Tom"; Console.WriteLine("Object.Equals(null, \"{1}\") => {2}", s1, s2, Object.Equals(s1, s2)); s1 = "Carol"; s2 = null; Console.WriteLine("Object.Equals(\"{0}\", null) => {2}", s1, s2, Object.Equals(s1, s2)); s1 = null; s2 = null; Console.WriteLine("Object.Equals(null, null) => {2}", s1, s2, Object.Equals(s1, s2)); } } /* This code produces the following output. Object.Equals("Tom", "Carol") => False Object.Equals("Tom", "Tom") => True Object.Equals(null, "Tom") => False Object.Equals("Carol", null) => False Object.Equals(null, null) => True */
Es wird überprüft, ob der Wert eines Objektes gleich ist.
Du kannst natürlich machen, was du willst. Aber deine Klasse möchte ich dann nicht im nächsten Framework haben.
dann würd ich das .NET Framework an deiner stelle nicht benutzen. Das wird nämlich überall gemacht.
Du sagst doch selber: "Equals() - Ob zwei (möglicherweise nicht die selben) Objekte den gleichen Zustand haben.". Dass prüft er ja, indem er die ID vergleicht.
Somit macht genau dass, was Equals machen soll (solange die ID eindeutig ist).
-
hmm. aber mache ich denn nicht genau das? Die Objekte vergleichen (egal, ob mit == oder Equal) und anhand des Merkmals Id entscheiden, ob sie es nun sind oder nicht?
Ach übrigens, Id ist genau sowas, wie bei einer Klasse "Konto" die Werte BLZ und KontoNr zusammen. Also die eindeutige Enterscheidung. Ist das dann nicht korrekt?
Ich möchte gerne darüber diskutieren, denn ich bin offen für Kritik / Rat, da ich schon sauber programmieren möchte.
-
Betrag editiert. Ich wollt mirs erst verkneifen Das edititeren hab aber recht lange gedauert, dashalb die verzögerung. Das Forum spinnt mal wieder
-
Equals() - Ob zwei (möglicherweise nicht die selben) Objekte den gleichen Zustand haben. Bsp.: Zwei verschiedene Brüche, die den selben Wert haben
=> logische GleichheitOk, was macht dann der == Operator? ist der gleichzusetzen mit Equal? Soll der die Referenzen prüfen?
Ich kann ja nochmal schreiben, worum es mir geht:
Ich habe Objekte des Typ CollisionMaterial in einer Liste. Ich möchte vermeiden, dass ich die gleichen Objekte mehrmals in die Liste packe. Dafür reicht aber nicht ein list.Contains (welches wohl die Referenzen prüft). Denn die Objekte können durchaus verschieden sein. Wenn sie aber die gleiche Id haben, möchte ich das zweite Objekt NICHT in die Liste packen, sondern es verwerfen.
-
Glaub mir, ich weiss, wie Equals() im Framework verwendet wird.
Du sagst doch selber: "Equals() - Ob zwei (möglicherweise nicht die selben) Objekte den gleichen Zustand haben.". Dass prüft er ja, indem er die ID vergleicht.
Genau die ID ist das, was er nicht vergleichen soll. Wenn du z.B. Autos mit Equals() vergleichst, musst du vergleichen, ob sie die selbe Farbe haben, die selbe Automarke, die selben Extras und nicht ob es die selben sind.
Somit macht genau dass, was Equals machen soll (solange die ID eindeutig ist).
Genau dann eben nicht. Wenn die ID eindeutig ist, dann macht es nämlich nicht das, was Equals machen soll, weil es nur true liefert, wenn es die selben Objekte sind.
Wenn er jetzt zwei CollisionMaterials hat, die genau den gleichen Inhalt haben, liefert sein Equals() false, außer es sind wirklich die selben Objekte. Equals soll aber true liefern, wenn zwei Objekte logisch gleich sind.Bitte denk doch mal kurz darüber nach: Equals soll Objektgleichheit feststellen und nicht Objektidentität. Anders wäre es auch Bullshit, denn dafür müsste er nur die Referenzen vergleichen.
Dir ist doch der Unterschied zwischen Objektgleichheit und Objektidentität klar?Jetzt überleg: Er vergleicht eindeutig IDs, das heisst er könnte auch gleich die Referenzen vergleichen. Ist es wirklich das, was Equals machen soll?
-
Ok, was macht dann der == Operator? ist der gleichzusetzen mit Equal? Soll der die Referenzen prüfen?
Jetzt hast du die richtige Frage gestellt.
Der operator== vergleicht standardmäßig die Referenzen! Das heisst, es liefert nur true, wenn es die selben (identischen, die selben Instanzen, ...) Objekte sind. Wenn du dieses Verhalten willst, dann brauchst du diesen Operator nicht zu redefinieren.Equals() dagegen soll die logische Gleichheit von zwei Objekten prüfen. Es können zwei verschiede Objekte den selben logischen Zustand haben und Equals muss dann true liefern.
Du kannst natürlich, wenn du es willst, operator== so redefinieren, dass es auch die logische Gleichheit feststellt (also praktisch Equals() aufruft). Aber dann ist es falsch, eindeutige IDs zu vergleichen, weil das ist ja wieder die Identität. Wenn du die Identität wirklich willst, dann lass den Operator so wie er ist.
-
Ja, mir ist es schon klar, was Du meinst, und ich gebe dir auch eigentlich Recht. Aber folgendes Problem habe ich:
Ich lese wie gesagt eine Xml-Datei ein. Irgendwo werden CollisionMaterials definiert (mit einer Id und sonstigen Attributen). An anderer Stelle verweisen andere "Objekte" auf eine MaterialId. Ich kann natürlich nicht vorher prüfen, ob genau diese Id auch wirklich oben definiert wurde.
Nun wolte ich, falls das referenzierte CollisionMaterial nicht gefunden wird, ein neues erzeugen.
-
Genau die ID ist das, was er nicht vergleichen soll. Wenn du z.B. Autos mit Equals() vergleichst, musst du vergleichen, ob sie die selbe Farbe haben, die selbe Automarke, die selben Extras und nicht ob es die selben sind.
ja, Man muss die Eigenschaften des Uatos vergleichen, und prüfen ob alles identisch ist. Genau.
Die Id der Klasse CollisionMaterial ist eine Eigenschaft. Es prüft doch gar nicht, ob die Instance A und die Instance B die selben sind. Sondern ob die Eigenschaften die selben sind. Genau wie du sagst.
Wenn die ID eindeutig ist, dann macht es nämlich nicht das, was Equals machen soll, weil es nur true liefert, wenn es die selben Objekte sind.
Um auf dein Auto zurückzukommen. Wenn ein Auto rot ist und das andere schwarz ist, gibt er false zurück. Wenn nur Autos produziert werden, die stehts eine einmalige Lackierung haben, gibt er nur true zurück, wenn es das selbe auto ist.
Die Vorgehensweise richtig. Die Tatsache, dass die ID Eindeutig ist, spielt dabei keine Rolle und ist nur Inhaltlich von Bedeutung.
-
Warum eine ID? Wird über die ID das entsprechende Objekt gefunden (array oder was auch immer)?
Dann lasst sie doch direkt auf ihr Objekt zeigen.Hat sogar noch den Vorteil, dass es der GC nicht aus Versehen fressen kann, obwohl du es noch brauchst.
Du willst keine Elemente doppelt haben? Willst du nicht die selben Elemente doppelt haben, oder die gleichen?
-
AndreasW schrieb:
Die Tatsache, dass die ID Eindeutig ist, spielt dabei keine Rolle und ist nur Inhaltlich von Bedeutung.
Findest du? Es kann also keine zwei logisch gleiche Objekte Objekte geben, da die ID eindeutig ist. Klingt für mich nach Prüfung auf Identität.
Logische Gleichheit heisst nicht, die Datenelemente alle zu vergleichen, sondern die Elemente zu vergleichen, die einen logischen Zustand definieren. Eine ID gehört IMHO nicht dazu.
-
Dir ist doch der Unterschied zwischen Objektgleichheit und Objektidentität klar?
klar
Beispiel- Vergleich:
string s1 = "Tom"; string s2 = "Carol"; object t1 = (object) s1; object t2 = (object) s2; s1 = "Tom"; s2 = "Tom"; Console.WriteLine("Object.Equals(\"{0}\", \"{1}\") => {2}", s1, s2, Object.Equals(s1, s2)); Console.WriteLine("test: {0} => {1} = {2}",s1, s2, t1==t2?"true":"false"); t2=t1; Console.WriteLine("test: {0} => {1} = {2}",s1, s2, t1==t2?"true":"false");
ergebnis: Object.Equals("Tom", "Tom") => True test: Tom => Tom = false test: Tom => Tom = true
-
genau das selbe kann man auch mit der ID machen.
Wie hier "Tom" wird die ID geprüft. Nicht ob die Instanzen gleich sind.Logische Gleichheit heisst nicht, die Datenelemente alle zu vergleichen, sondern die Elemente zu vergleichen, die einen logischen Zustand definieren. Eine ID gehört IMHO nicht dazu.
Was ist, wenn du in der ArrayList nur ein Tom drin haben willst. und bist fleissig am eintüten.
Dabei musst du dann stets prüfen, ob ein Element mit diesen Namen (ID) bereits in der Liste ist.
Dann machst du doch die Klasse über den Namen eindeutig um diese Logik in die Klasse einzubringen und den Zugriff auf die Klasse zu vereinfachen.
-
das macht natürlich nur Sinn, wenn die Operatoren später nicht für andere Vergleiche gebraucht werden, bedeutet es muss inhaltlich Richtig bleiben.
Seine Klasse heisst: 'CollisionMaterial'. Wenn er später andere Eigenschaften des Material über die Operatoren vergleichen möchte, macht ein es natürlich kein Sinn, die ID zur Prüfung auf Gleichheit zu nehmen. Dann gebe ich dir Recht und würd dann lieber beim Eintüten in die ArrayList die ID selbst vergleichen.
Aber dass ist eine inhaltliche Entscheidung und kein Problem der allgemeinen Handhabung von Equals oder den Operatoren.
-
Wow, da habe ich aber eine Diskussion angestoßen! Ist ja klasse.
Nun. Zunächst zu meinem eigentlichen Problem: Ich habe durch die Diskussion festgestelt, dass ich falsch lag in der ganzen Implementierungs-Idee. Ich kann nicht einfach ein neues Material erzeugen, wenn es eine Id nicht gibt. Es muss vorher in der Xml-Datei spezifiezert und parametrisiert sein. Es gibt nämlich in der Tat noch andere Eigetnschaften, die ich dann nicht festlegen könnte. Daher muss ich eine Exception schmeißen, ewnn es das Material nicht gibt.
Die Id brauche ich allerdings, da ich sonst das passende Material nicht mehr aus der Liste bekomme (vielleicht sollte man über eine Map (falls das in C# so heisst) nachdenken). Ich erzeuge die Materials ja zunächst, packe sie in die Liste und im nächsten, späteren Schritt suche ich sie wieder raus, wenn ich die referenzierenden Objekte erzeuge.
Habt Dank, dass ich so den logisch-inhaltlichen Fehler gefunden habe
Aber ich will mich auch an der Diskussion beteiligen. Ich denke eigentlich, dass wir gar nicht aneinander vorbeireden. Eigentlich besteht doch kein Zweifel (nachdem ich nun weiß, wozu Equals() da ist), was Identität und Gleichheit ist und dass Equals eben auf Gleichheit prüft.
Aber was ist der == Operator?? Auf Ebene von object prüft er (wie Equal()) die Referenzen -- was auch sonst -- und damit auf Identität. Bei String prüft er auf Gleichheit. Und was prüft er in der Theorie / Philosophie des Programmierens??
-
genau das selbe kann man auch mit der ID machen.
Wie hier "Tom" wird die ID geprüft. Nicht ob die Instanzen gleich sind.Ja, aber wenn die ID eindeutig ist? Dann werden die Instanzen geprüft.
Und (jetzt kommt der Punkt):
Wenn zwei Objekte gleich sind, aber die ID nicht, werden sie von diesem Equals() als "logisch ungleich" bewertet. Und das ist falsch.Dabei musst du dann stets prüfen, ob ein Element mit diesen Namen (ID) bereits in der Liste ist.
Dann machst du doch die Klasse über den Namen eindeutig um diese Logik in die Klasse einzubringen und den Zugriff auf die Klasse zu vereinfachen.Ja, natürlich musst du das prüfen. Kommt drauf an, was du für deine ArrayList willst: Ob kein Elemente doppelt drin sind, oder ob überhaupt keine logisch gleichen Elemente mehrmals drin sind. Das zweite ist natürlich aufwändig, aber es geht halt nicht anders. Deshalb sollte man mit Equals() auch immer die Methode um einen Hashcode zu getten (weiss grad nicht wie die heisst), redefinieren. Da kann man dann gut von profitieren, weil nicht jedesmal Equals() aufgerufen werden muss.
Aber dass ist eine inhaltliche Entscheidung und kein Problem der allgemeinen Handhabung von Equals oder den Operatoren.
Das sehe ich anders. Was er mit dem operator== macht, ist ja eigentlich egal (ich würde ihn nur bei so mathematischen Sachen wie Brüche auf Gleichheit prüfen lassen). Aber Equals soll nicht die Identität vergleichen, aber das wird hier mit der ID gemacht (Ich gehe jetzt immer noch davon aus, dass IDs eindeutig sind).
Was ich sowieso überhaupt schwachsinnig finde, weil da vergleiche ich gleich lieber die Referenzen.Ich weiss ehrlich gesagt nicht, warum du das wegdiskutieren willst. Es ist doch offensichtlich, dass hier, anstatt die Inhalte von so einem Material zu vergleichen die Identität (ID == Identität, das sagt ja der Name schon :p ) verglichen wird. Das ist doch Fakt. Dazu brauche ich mir doch nur den Sourcecode anschauen.
-
Aber was ist der == Operator?? Auf Ebene von object prüft er (wie Equal()) die Referenzen -- was auch sonst -- und damit auf Identität.
Nein, Equals soll nicht die Referenzen vergleichen. Das macht natürlich das Equals von Object, was willst du denn für Object auch ein anderes Equals definieren? Aber es ist so gedacht, dass es nicht die Referenz, sondern den Inhalt vergleicht.
Bei String prüft er auf Gleichheit. Und was prüft er in der Theorie / Philosophie des Programmierens??
Was du für richtig hältst. Ich halte meistens die Identität für richtig, weil ich mir vorstelle, mit Zeigern zu arbeiten und damit die Zeiger vergleiche.
Ne Ausnahme würde ich bei einer Klasse für Brüche oder Komplexe Zahlen machen. Und natürlich bei String, weil die Identität eines Strings eigentlich gar nichts nützt.