Gegen Internetzensur
Stoppt die Vorratsdatenspeicherung! Jetzt klicken & handeln!Willst du auch bei der Aktion teilnehmen? Hier findest du alle relevanten Infos und Materialien:
  • Flickr Photos

    www.flickr.com
22. Mai
Don

C# Code Snippets: operator== und Freunde

Ich weiß gar nicht, wieso ich mir früher so einen Stress gemacht habe.
Für bestimmte Klassen oder Strukturen ist es nötig, Relationsoperatoren zu implementieren. Nehmen wir das klassische Beispiel einer Struktur, die eine komplexe Zahl darstellt. Diese hat einen Real- und einen Imaginäranteil, aber weil sie eben kein primitiver Typ ist (z.B. eine Zahl), weiß das System auch nicht, wie man sie verrechnen, geschweige denn vergleichen soll – woher auch?

Für den Relationstest gibt es typischerweise sechs Operatoren: ==, !=, <, <=, > und >=. Im Falle einer komplexen Zahl ist die Geschäftslogik dahinter noch sehr überschaubar, aber wenn es einmal komplizierter wird, kann das auch unter Zuhilfenahme von Dr. Copy und Mr. Paste schon anstrengend werden.

Man kommt allerdings auch mit nur zwei sauber implementierten Operatoren aus, die restlichen vier lassen sich dann mit einfachen Kombinationen daraus abbilden. Folgende Überlegung dazu:

  • a == b wird negiert zu a != b,
  • a != b wird negiert zu a == b,
  • a < b wird negiert zu a >= b,
  • a > b wird negiert zu a <= b,
  • a <= b wird negiert zu a > b und
  • a >= b wird negiert zu a < b

Wenn man nun also operator==() implementiert, hat man operator!=() bereits kostenlos in der Tasche:

  1. class Ding {
  2.     int a, b, c, d;
  3.  
  4.     // sauber implementiert
  5.     public static operator == (Ding dong) {
  6.         return a==dong.a && b==dong.b && c==dong.c && d==dong.d;
  7.     }
  8.  
  9.     public static operator != (Ding dong) {
  10.         return !( this == dong );
  11.     }
  12. }

Ähnlich verhält es sich mit den restlichen vier Relationen. Wenn wir nun noch einen weiteren Operator implementieren, z.B. <, …

  1. // sauber implementiert
  2.     public static operator < (Ding dong) {
  3.         return a<dong.a && b<dong.b && c<dong.c && d<dong.d;
  4.     }

... dann können wir die anderen aus dem bisherigen Bestand ableiten:

  1. public static operator < = (Ding dong) {
  2.         return (this < dong) || (this == dong);
  3.     }
  4.  
  5.     public static operator > (Ding dong) {
  6.         return !(this < = dong);
  7.     }
  8.  
  9.     public static operator >= (Ding dong) {
  10.         return !(this < dong );
  11.     }

In optimierten Builds sollten sich die überschüssigen Funktionsaufrufe dann auch großteils wegrationalisieren lassen - ich habe das allerdings nicht getestet. Wenn nicht, ist es aber auch nicht weiter wild: Wenn man die Zeit und Ruhe dafür hat und es wirklich um die Performance geht, kann man das ja alles immer noch ausformulieren.

Ist natürlich keine wilde Sache, aber besser man sagt's mal, bevor so Deppen wie ich sich halb die Finger wundprügeln und dann doch mal was übersehen. (Und geraume Zeit später auf Fehlersuche gehen :mrgreen:)

Die Kommentarfunktion ist geschlossen.