2016-08-30 4 views
2

Der folgende Code hat ein Laufzeitproblem mit unerwarteten Verweisen durch Zuweisung von Postfix/Präfix Inkrementanweisung wie im folgenden Code gezeigt. Kann mir jemand bitte einen Weg vorschlagen, Objekte als Werttypen in C# zu behandeln, wie es unter anderem vorgeschlagen wird?Präfix und Postfix-Operator überladen in C#

Ich glaube, dass der Code gut dokumentiert ist mit Kommentaren jeden wichtigen Zustand zu klären. Fühlen Sie sich frei, irgendwelche Fragen bezüglich der Klärung des Codes oder des vorliegenden Problems zu stellen.

Vielen Dank im Voraus.

class Test { 

    public int x; 

    public Test(int x) { this.x=x; }  
    public Test() { x=0; } 

    static public Test operator++(Test obj) { 
     return new Test(obj.x+1); 
    } 
} 

// In implementing module 
// Prefix/Postfix operator test for inbuilt (scalar) datatype 'int' 
int x=2; 
int y=++x; // 'y' and 'x' now both have value '3' 
Console.WriteLine(x++); // Displays '3' 
Console.WriteLine(++x); // Displays '5' 
Console.WriteLine(ReferenceEquals(x,y)); // Displays 'False' 


// Prefix/Postfix operator test of class type 'Test' 
Test obj=new Test(); 
obj.x=1; 
Console.WriteLine(obj++); // Must have displayed '1', displays the object type (Test.Test) 
Console.WriteLine(++obj); // Must have displayed '3', again displays the object type (Test.Test) 
Console.WriteLine(obj.x); // Displays '3' (as expected) 

Test obj2=++obj; // Must have the value '4' and must NOT be the reference of obj 
// Alternative solution to the above statement can be : 'Test obj2=new Test(++obj);' but isn't there a way to create a new value type in C# by the above statement ??!! (In C++, it can be acheived by overloading the '=' operator but C# doesn't allow it) 
Console.WriteLine(obj2.x); // Displays '4' (as expected) 
Console.WriteLine(ReferenceEquals(obj,obj2)); // Must display 'False' but displays 'True' showing that 'obj2' is the reference of 'obj' 
+2

Nun ja, Sie haben 'ToString()' nicht überschrieben. An diesem Punkt geht die Hälfte Ihrer Einwände weg. Es würde wirklich helfen, wenn du ein [mcve] schreibst, das ein * single * Problem demonstriert. –

+0

@ user3185569: Ich habe dieses Bit des Kommentars entfernt. Es sieht für mich so aus, als ob der Teil über 'obj' und' obj2' in Ordnung sein sollte ... Es hilft nicht, dass es hier so viele zusammenhängende Probleme gibt. –

+0

Eigentlich nein, ich sehe, was mit dem 'Test obj2 = ++ obj' Teil falsch ist. Wird eine Antwort dafür hinzufügen. –

Antwort

1

Sie versuchen, einen Typ anzupassen, der als class deklariert ist, um sich als struct zu verhalten. Das ergibt für mich keinen Sinn. Wenn Sie class Test zu struct Test ändern, den parameterlosen Konstruktor entfernen und die .ToString-Methode überschreiben, sind alle Probleme verschwunden.

Zuerst erstellen Sie bei jedem Inkrementieren (Post oder Pre) eine neue Instanz von Test.Also, wenn Sie trifft diese Zeile:

Als ob Sie schreiben:

obj = new Test(obj.x + 1); 
Test obj2 = obj; 

Zweite und wie für das Druckproblem, außer Kraft setzt nur das ToString:

public override string ToString() 
{ 
    return x.ToString(); 
} 
+0

Nun, wie kann ich sie nicht die gleiche Referenz haben? Danke für die Antwort. – hecate

+0

@hecate Dann gibt es keinen Grund, "Test" als eine Klasse zu haben, wenn Sie nicht möchten, dass es als Referenz behandelt wird. Konvertiere es dann in ein 'Struct'. Dadurch haben Sie eine Kopie nach Wert Semantik und dieses Problem ist weg. – user3185569

+0

Danke. Das Konvertieren der 'Test'-Klasse in eine Struktur half. Nochmals vielen Dank :) – hecate

1

Wenn Sie lesen die link Sie auf die gelöschte Antwort zur Verfügung gestellt, so gilt:

Ist übersetzt

temp = operator++(obj); 
obj = temp; 
obj2 = temp; 

Was bedeutet sie die gleiche Referenz.

+0

Na dann, wie kann ich sie nicht die gleiche Referenz haben? Danke für die Antwort. – hecate

+0

Sie können nicht, wenn Sie nur den Operator ++ verwenden möchten. Nur eine Instanz wird für die "erhöhte" Version erstellt. – Maarten

4

Grundsätzlich haben Sie falsch verstanden, wie diese Linie funktioniert:

Wenn Sie glauben, dass Ihr Bediener als eine Methode zu verwenden, das ist, wie wenn man sagt:

obj = Test.operator++(obj); 
obj2 = obj; 

Also ja, Sie am Ende mit obj und obj2 die gleiche Referenz sein. Das Ergebnis von ++obj ist der Wert objnach mit dem Operator ++, aber der Operator ++ wirkt sich auch auf den Wert obj aus.

Wenn Sie

Test obj2 = obj++; 

dann ist das äquivalent zu:

Test tmp = obj; 
obj = Test.operator++(obj); 
obj2 = tmp; 

An diesem Punkt wird der Wert von obj2 wird auf das ursprüngliche Objekt beziehen, und die vlaue von obj wird auf die beziehen neu erstelltes Objekt mit einem höheren Wert x.

Der Rest Ihrer Frage rund um das Ergebnis von ist wirklich, weil Sie ToString() nicht überschrieben haben.

+0

Nun, wie kann ich sie nicht die gleiche Referenz haben? Danke für die Antwort. – hecate

+0

@hecate: Sie können nicht. Sehen Sie sich an, was 'Test obj2 = ++ obj;' bedeutet - der letzte Teil davon ist 'obj2 = obj;'. Wie würden Sie davon ausgehen, dass Sie unterschiedliche Referenzen geben? Beachten Sie, dass, wenn "Test" unveränderlich ist, es keine Rolle spielen sollte. (Wie an anderer Stelle angemerkt, können Sie eine Struktur "testen", aber dann gibt es keine Referenzen irgendwo ...) –