it-swarm.com.de

Der Rückgabewert Fehler c # kann nicht geändert werden

Ich verwende automatisch implementierte Eigenschaften. Ich denke, der schnellste Weg, das Problem zu beheben, besteht darin, meine eigene Backing-Variable zu deklarieren.

public Point Origin { get; set; }

Origin.X = 10; // fails with CS1612

Fehlermeldung: Der Rückgabewert von 'expression' kann nicht geändert werden, da es ist keine Variable

Es wurde versucht, einen Werttyp zu ändern, der das Ergebnis eines Zwischenausdrucks war. Da der Wert nicht beibehalten wird, bleibt der Wert unverändert. 

Um diesen Fehler zu beheben, speichern Sie das Ergebnis des Ausdrucks in einem Zwischenwert oder verwenden Sie einen Referenztyp für den Zwischenausdruck.

110
P a u l

Dies liegt daran, dass Point ein Werttyp ist (struct).

Wenn Sie auf die Origin-Eigenschaft zugreifen, greifen Sie daher auf eine copy des Werts der Klasse zu, nicht auf den Wert selbst wie bei einem Referenztyp (class). Wenn Sie also die X-Eigenschaft festlegen Daraufhin legen Sie die Eigenschaft für die Kopie fest und verwerfen sie, wobei der ursprüngliche Wert unverändert bleibt. Dies ist wahrscheinlich nicht das, was Sie beabsichtigt haben, weshalb der Compiler Sie darauf hinweist.

Wenn Sie nur den X-Wert ändern möchten, müssen Sie Folgendes tun:

Origin = new Point(10, Origin.Y);
156
Greg Beech

Die Verwendung einer Backing-Variablen hilft nicht. Der Typ Point ist ein Werttyp.

Sie müssen der Origin-Eigenschaft den gesamten Point-Wert zuweisen: -

Origin = new Point(10, Origin.Y);

Das Problem ist, dass beim Zugriff auf die Origin-Eigenschaft eine von der get zurückgegebene Kopie der Point-Struktur im automatisch erstellten Origin-Eigenschaftenfeld angezeigt wird. Ihre Änderung des X-Feldes würde diese Kopie also nicht auf das darunterliegende Feld auswirken. Der Compiler erkennt dies und gibt einen Fehler aus, da dieser Vorgang völlig nutzlos ist.

Selbst wenn Sie Ihre eigene Backing-Variable verwenden würden, würde Ihre get folgendermaßen aussehen: -

get { return myOrigin; }

Sie würden immer noch eine Kopie der Point-Struktur zurückgeben und erhalten dieselbe Fehlermeldung. 

Hmm ... nachdem Sie Ihre Frage etwas genauer gelesen haben, meinen Sie vielleicht, die Hintergrundvariable direkt aus Ihrer Klasse heraus zu ändern: -

myOrigin.X = 10;

Ja, das wäre was Sie brauchen würden.

7
AnthonyWJones

Inzwischen wissen Sie bereits, wo der Fehler liegt. Wenn kein Konstruktor vorhanden ist, der überlastet ist, um Ihre Eigenschaft zu übernehmen (in diesem Fall X), können Sie den Objektinitialisierer verwenden (der die gesamte Magie hinter den Kulissen beherrscht). Nicht dass Sie Ihre Strukturen nicht unveränderlich machen müssen, sondern nur zusätzliche Informationen angeben:

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

class MyClass
{
    public Point Origin { get; set; }
}

MyClass c = new MyClass();
c.Origin.X = 23; //fails.

//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor

//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.

Dies ist möglich, weil dies im Hintergrund geschieht:

Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;

Dies sieht nach einer sehr seltsamen Sache aus, wird überhaupt nicht empfohlen. Geben Sie einfach einen alternativen Weg an. Die beste Möglichkeit ist, struct unveränderlich zu machen und einen geeigneten Konstruktor bereitzustellen.

4
nawfal

Ich denke, der Haken ist, dass Sie versuchen, die Unterwerte des Objekts in der Anweisung zuzuweisen, anstatt das Objekt selbst zuzuweisen. In diesem Fall müssen Sie das gesamte Point-Objekt zuweisen, da der Eigenschaftstyp Point ist.

Point newOrigin = new Point(10, 10);
Origin = newOrigin;

Ich hoffe, ich habe dort Sinn gemacht

0
MSIL

Das Problem ist, dass Sie auf einen Wert zeigen, der sich im Stapel befindet, und der Wert wird nicht wieder auf die Eigenschaft orignal zurückgesetzt, sodass Sie in C # keinen Verweis auf einen Werttyp zurückgeben können. Ich denke, Sie können dieses Problem lösen, indem Sie die Origin-Eigenschaft entfernen und stattdessen ein öffentliches Feld verwenden. Ja, ich weiß, es ist keine Nizza-Lösung. Die andere Lösung besteht darin, den Point nicht zu verwenden und stattdessen einen eigenen Point-Typ als Objekt zu erstellen.

0
Fredrik Normén

Abgesehen von der Diskussion der Vor- und Nachteile von Strukturen gegen Klassen, neige ich dazu, das Ziel zu betrachten und das Problem aus dieser Perspektive zu betrachten.

Wenn Sie jedoch keinen Code hinter den Property-Get- und-Set-Methoden schreiben müssen (wie in Ihrem Beispiel), wäre es nicht einfacher, die Variable Origin einfach als Feld der Klasse und nicht als Eigenschaft zu deklarieren. Ich denke, das würde Ihnen erlauben, Ihr Ziel zu erreichen.

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

class MyClass
{
    public Point Origin;
}

MyClass c = new MyClass();
c.Origin.X = 23;   // No error.  Sets X just fine
0
Mitselplik