Probleme mit überladenem operator ==
-
Hi,
ich wollte in C# den Vergleichsoperator == überladen. Leider gibt es Probleme, wenn ich eine Referenz auf null prüfen will. Hier ist mein Code:
public class CollisionMaterial { private int id; ... public override bool Equals(object o) { return id == ((CollisionMaterial) o).Id; } public static bool operator ==(CollisionMaterial m1, CollisionMaterial m2) { return m1.Equals(m2); } public static bool operator !=(CollisionMaterial m1, CollisionMaterial m2) { return !m1.Equals(m2); } public override int GetHashCode() { return id; } } ... // ANDERE METHODE EINER ANDEREN KLASSE: // GetItemById() durchsucht eine Liste und gibt Referenz oder null zurück CollisionMaterial mat = collisionMaterials.GetItemById(materialId); if(mat == null) { ... }
die Zeile if(mat == null) erzeugt leider eine Exception, und zwar mit der Message: "der objektverweis wurde nicht auf eine Objektinstanz festgelegt" (bzw. englisch "Object reference not set to an instance of an object").
Wie überlädt man denn den operator oder genauer die Equals-Methode so, dass man auch auf null prüfen kann? Das ist sehr wichtig und ich brauche diesen Test...
-
public override bool Equals(object o) { return id == ((CollisionMaterial) o).Id; // hier ist die Ursache }
ein cast von null nach "CollisionMaterial" ergibt null. Und dann null.ID ergibt eine Exception. Nämlich die erwähnte;
public override bool Equals(object o) { return id == (o==null?null:((CollisionMaterial) o).Id); // so vielleicht besser }
-
nee, das klappt nicht. war gut gemeint, aber es ändert gar nix. selbe exception...
wobei ich es so machen musste:
if(o == null) return false; return id == ((CollisionMaterial) o).Id;
-
Ein einfaches
public override bool Equals(object o) { readonly CollisionMaterial bla = o as CollisionMaterial; if( bla == null ) return false; else return (id == bla.id); }
würde es doch tun, oder?
(EDIT: ups, in C# gibts kein final )
-
public override bool Equals(object o) { CollisionMaterial temp=(CollisionMaterial) o; if(temp !=null) return id == temp.Id; else return false; }
oder so ähnlich. selbst ist der Mann...
-
Felix: Deine Methode kackt ab, wenn Object kein CollisionMaterial ist.
-
falls du "CollisionMaterial bla = o as CollisionMaterial;" meinst, nee, klappt auch nicht....
Das kan doch gar nicht so schwierig sein. Mit String oder so klappt das doch auch.
-
oh, und noch ne frage: was ist denn "as" für ein Operator / Keyword? Bin noch icht soo lange bei C# dabei.
-
oh
ja, er war schnelleraufgepasst:
public static bool operator ==(CollisionMaterial m1, CollisionMaterial m2) { return m1.Equals(m2); // wer garantiert dir, dass m1 nicht null ist ? dieser Zugriff ist geführlich. Genau das selbe Problem wie in Equals }
-
man, ist das durcheinander. wieso schreiben wir denn alle gleichzeitig. Naja,
@andreas
aber wie mache ich denn dann? Das leuchtet mir schon ein, dass das gefährlich ist.
-
also,
CollisionMaterial temp=(CollisionMaterial) o; if(temp !=null) return id == temp.Id; else return false;
funktioniert auch nicht. Zudem benutze ich dann ja den != operator, den ich ebenfalls überschreibe und welcher auch mit Equals prüft.
-
Was klappt an meiner Methode nicht? Du willst doch anhand der id feststellen, ob zwei Objekte gleich sind, oder?
(Was übrigens keine gute Vorgehensweise ist. Equals sollte nicht prüfen, ob das die selben beiden Objekte sind, sondern ob sie logisch gleich sind. Ich gehe mal davon aus, dass es jede id nur einmal gibt.)
Wenn du wirklich prüfen willst, ob es die absolut selben Objekte sind, warum vergleichst du dann nicht die Referenzen einfach?
-
Hi,
Debuggen == programmieren
public override bool Equals(object o) { CollisionMaterial temp=(CollisionMaterial) o; if(temp !=null) return id == temp.Id; else return false; } public static bool operator ==(CollisionMaterial m1, CollisionMaterial m2) { CollisionMaterial temp=(CollisionMaterial) o; if(temp !=null) // setze hier mal einen Haltepunkt. und stepp dann langsam duch. Schuen im Fenster "local" die Zustände der lokalen Variablen an return m1.Equals(m2); else return m2==null; }
-
Frei nach Andreas' Motto "selbst ist der Mann" habe ich gerade die Lösung gefunden:
Das Problem lag nämlich in der Tat darin, dass beim Aufruf if(mat == null) natürlich mat wirklich null ist. Und dann knallt es im operator ==.
Ergo: vorher testen, ob m1 null ist. Sieht zwar jetzt nicht schön aus, klappt aber.public override bool Equals(object o) { if(o == null) return false; CollisionMaterial tmp = (CollisionMaterial) o; return id == tmp.Id; } public static bool operator ==(CollisionMaterial m1, CollisionMaterial m2) { if(((object)m1) == null) { if(((object) m2) == null) return true; return false; } return m1.Equals(m2); } public static bool operator !=(CollisionMaterial m1, CollisionMaterial m2) { if(((object)m1) == null) { if(((object) m2) == null) return false; return true; } return !m1.Equals(m2); }
-
übrigens: gefunden durch das Verwenden von Haltepunkten
-
hehe,
in euIRC #net wäre es einfacher, wenn man eh in Chat-Tempo postet
-
if(((object)m1) == null)
Das ist völlig Schwachsinn. Und warum benutzt du nicht den Operator as, mit dem sich das um einiges schöner schreiben lässt?
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 stimt vielleicht
Naja, vielen Dank auf jeden Fall. Meint ihr, dass es noch einfacher geht?
-
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.
-
Hm, die Datenbank war gerade weg, aber jetzt kann es ja weiter gehen.
- mit Java habe ich kein Problem -- da komme ich eigentlich her. Ich denke auch, dass meine Implementierung alles erfüllt. Allerdings habe ich auch auf den Optimizer gehört und sie wie folgt geändert. Damit fange ich den Fall ab, dass Objekte anderer Klassen übergeben werden:
public override bool Equals(object o) { CollisionMaterial tmp = o as CollisionMaterial; if(tmp == null) return false; return id == tmp.Id; }
- if(((object)m1) == null) ist NICHT schwachsinn. Ich muss uzm object casten, da ich sonst immer den überladenen operator aufrufe und so einen Stack-Overfow bekomme...
-
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.