C# - So 17.08.14 15:41
Titel: Operatoren Überladen: Ich steh auf dem Schlauch -.-
Hey Leute,
irgendwie hänge ich gerade beim Überladen von Operatoren. Ich will mir eine kleine Bibliothek schreiben um mir den Alltag ein wenig zu erleichtern :)
Ich bin mir nicht sicher ob ich die Operatoren richtig überlade, denn ich bekomme bei allen Methoden den Fehler: "Einer der Parameter eines binären Operators muss der enthaltende Typ sein". Ich habe den anderen Thread hier im Forum zu dem Thema gelesen, aber ich habe ja nur einfache Standardtypen und verwende <T> nicht.
Kann ich die Überladungen einfach so in eine Klasse packen oder ist dass das Problem? Einer der Operatoren entspricht ja dem Rückgabetyp :/
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| namespace Extensions { public class Geometry { public static SizeF operator *(SizeF size, float scale) { return new SizeF(size.Width * scale, size.Height * scale); }
public static SizeF operator *(SizeF size, int scale) { return new SizeF(size.Width * scale, size.Height * scale); }
public static SizeF operator *(SizeF size, SizeF scale) { return new SizeF(size.Width * scale.Width, size.Height * scale.Height); }
public static PointF operator *(PointF point, SizeF scale) { return new PointF(point.X * scale.Width, point.Y * scale.Height); }
public static Point operator *(Point point, Size scale) { return new Point(point.X * scale.Width, point.Y * scale.Height); } } } |
Das ist der komplette Code
EDIT
Habe gerade in der msdn-Doku nachgeschaut. Hat sich erledigt :)
EDIT 2
Was mich zu der Frage bringt: Kann man Operatoren von Typen auch außerhalb ihrer Klasse / Struktur überladen? Also so wie ich es oben gerne hätte.
Palladin007 - So 17.08.14 23:09
Das funktioniert nur, wenn beide Klassen/Strukturen im selben Namenspace und dem selben Projekt liegen, wenn sie den selben Namen haben und beide als partial markiert wurden.
Da Point in System.Drawing.dll liegt, geht das nicht, selbst wenn sie als partial markiert worden wäre.
Wenn ich das richtig verstehe, möchtest du Operator-Überladungen zu einem bestehenden Typ hinzu fügen.
Ein Operator wird immer auf auf mindestens ein Objekt ausgeführt und dieses Objekt legt die möglichen Operatoren fest. Woher soll der Compiler denn wissen, wo er die Operatoren suchen soll, wenn die Datentypen, auf die verwendet wurden, diese Operatoren nicht anbietet?
Du kannst das nur lösen, indem du eine neue Klasse/Struktur erstellst und von der Alten ableitest. Dort kannst du dann Operatoren überladen und auch nutzen.
Aber auch da wirst du Schwierigkeiten haben, denn die Strukturen, die du willst, sind alle
sealed und können damit nicht als Basistyp dienen.
Eine letzte Möglichkeit hast du noch:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| public struct PointFDecorator { public static implicit operator PointFDecorator(PointF point) { return new PointFDecorator(point); } public static implicit operator PointF(PointFDecorator point) { return point.Point; }
public static PointF operator *(PointF point, SizeF scale) { return new PointF(point.X * scale.Width, point.Y * scale.Height); } private readonly PointF _point;
public PointF Point { get { return _point; } }
public PointFDecorator(PointF point) { _point = point; } } |
Aufruf dann so:
C#-Quelltext
1: 2: 3: 4:
| PointFDecorator point = new PointF(1, 2); var size = new SizeF(3, 4);
PointF x = point * size; |
Wirklich schön finde ich das aber auch nicht. Ich glaube, ich würde mir da eher eine statische Helper-Klasse schreiben, wie bei der Path-Klasse.
Die stellt dann deine Operatoren als statische Methoden bereit.
Allgemein nutze ich recht selben die Operator-Überladung, die hat nämlich den Nachteil, dass man nicht auf den ersten Blick erkennt, was da passiert.
Es gibt keinen Namen, den man deuten kann, sondern nur ein Zeichen. Ich finde, das würde sich negativ auf die Lesbarkeit des Codes auswirken.
Edit:
Mir fällt gerade auf, dass die Fehlermeldung, die du bekommen hast, scheinbar nicht ganz stimmt:
Zitat: |
Einer der Parameter eines binären Operators muss der enthaltende Typ sein |
Allerdings entspricht hier keiner der Typen dem enthaltenden Typ:
C#-Quelltext
1:
| public static PointF operator *(PointF point, SizeF scale) { } |
Ich vermute mal, es müsste sowas in der Richtung heißen, dass einer der Typen in den enthaltenden Typ gecastet werden kann.
Das würde dann nämlich zu treffen, denn dafür habe ich die beiden ersten Überladungen eingebaut. Wenn ich das von implicit auf explicit (braucht beim Cast den konkreten Ziel-Typ in Klammern) ändere, dann bekomme ich den gleichen Fehler.