Autor Beitrag
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: So 17.08.14 15:41 
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 :/

ausblenden 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.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: So 17.08.14 21:59 
Laut der Fehlermeldung geht gernau das eben nicht.

Was du natürlich machen kannst: In einer Datei (Operatoren.cs) diverse (partial) classes mit den Operatoren auflisten. Also die Operatoren alle in eine Datei auslagern. Fände ich persönlich aber unpraktisch.
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: So 17.08.14 22:17 
Das dachte ich mir schon... Wie kann ich die Typen dann in partialen Klassen auslagern?
Wenn ich
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
namespace System.Drawing
{
    public partial struct Point
    {

    }
}

mache, habe ich einen neuen Typ erstellt und nicht den Alten erweitert.

Kannst du mal ein Codeschnipsel posten wie das funktioniert?

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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:

ausblenden 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:

ausblenden C#-Quelltext
1:
2:
3:
4:
PointFDecorator point = new PointF(12);
var size = new SizeF(34);

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:

ausblenden 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.

Für diesen Beitrag haben gedankt: C#
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mo 18.08.14 15:09 
Vielen Dank für die Erklärung. Das ganze wäre dann doch ein recht großer Aufwand. Ich denke ich wechsel dann zu Extension Methods.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 18.08.14 17:32 
Oder so

Ich bin auch der Meinung, Operatoren solltest du nur überladen, wenn du genau weißt, dass das, was dort erledigt wird, überall und bei jedem Entwickler gleich aufgefasst werden wird und selbstverständlich ist. Bei Int32 sind das die Grundrechenarten und die sind, wie ich finde, mehr als selbstverständlich.

Für alles Andere wirst du bei mir Methoden finden