Błąd:" nie można zmienić wartości zwracanej " c#

Używam auto-zaimplementowanych właściwości. Myślę, że najszybszym sposobem, aby naprawić następujące jest zadeklarować własną zmienną zaplecza?

public Point Origin { get; set; }

Origin.X = 10; // fails with CS1612

Komunikat o błędzie: Nie można zmienić wartości zwracanej wyrażenia, ponieważ nie jest zmienną

Podjęto próbę modyfikacji typu wartości, który był wynikiem ekspresja pośrednia. Ponieważ wartość nie jest utrzymywana, wartość będzie bez zmian.

Aby rozwiązać ten błąd, zapisz wynik o wyrażeniu w wartość pośrednia, lub użyć typu odniesienia dla pośredniego ekspresja.

Author: StayOnTarget, 2009-11-17

8 answers

Dzieje się tak dlatego, że Point jest typem wartości (struct).

Z tego powodu, kiedy uzyskujesz dostęp do Właściwości Origin, uzyskujesz dostęp do kopii wartości przechowywanej przez klasę, A nie samej wartości, jak w przypadku typu reference (class), więc jeśli ustawisz na niej właściwość X, to ustawiasz właściwość na kopii, a następnie odrzucasz ją, pozostawiając oryginalną wartość bez zmian. To prawdopodobnie nie jest to, co zamierzałeś, dlatego kompilator ostrzega Cię przed to.

Jeśli chcesz zmienić tylko wartość X, musisz zrobić coś takiego:

Origin = new Point(10, Origin.Y);
 211
Author: Greg Beech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-17 09:49:02

użycie zmiennej pomocniczej nie pomoże. typ Point jest typem wartości.

Musisz przypisać wartość całego punktu do Właściwości Origin:-

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

Problem polega na tym, że gdy uzyskujesz dostęp do Właściwości Origin, to co jest zwracane przez {[4] } jest kopią struktury punktu w automatycznie utworzonym polu Właściwości Origin. Stąd twoja modyfikacja Pola X ta kopia nie wpłynie na pole bazowe. Kompilator wykrywa to i daje błąd, ponieważ to operacja jest całkowicie bezużyteczna.

Nawet jeśli użyjesz własnej zmiennej nośnej, Twoje get wyglądałoby tak:-

get { return myOrigin; }

Nadal zwracałbyś kopię struktury punktowej i otrzymałbyś ten sam błąd.

Hmm... po dokładniejszym zapoznaniu się z twoim pytaniem, być może chcesz zmodyfikować zmienną podkładową bezpośrednio z poziomu swojej klasy: -

myOrigin.X = 10;
Tak, właśnie tego byś potrzebował.
 10
Author: AnthonyWJones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-27 15:29:27

Już wiesz, co jest źródłem błędu. W przypadku, gdy konstruktor nie istnieje z przeciążeniem, aby zabrać twoją własność( w tym przypadku X), możesz użyć inicjalizatora obiektu (który wykona całą magię za kulisami). nie dlatego, że nie musisz zmieniać swoich struktur , ale po prostu podając dodatkowe informacje:

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.

Jest to możliwe, ponieważ dzieje się to za kulisami:

Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
To wygląda na bardzo dziwną rzecz do zrobienia. polecam. Wymieniam alternatywny sposób. Lepszym sposobem jest uczynienie struktury niezmienną i dostarczenie odpowiedniego konstruktora.
 7
Author: nawfal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 21:28:35

Poza dyskusją o zaletach i wadach struktur kontra klas, mam tendencję do patrzenia na cel i podejścia do problemu z tej perspektywy.

Jeśli nie musisz pisać kodu za właściwością get I set methods (jak w twoim przykładzie), to czy nie byłoby łatwiej zadeklarować Origin jako pole klasy, a nie Właściwość? Myślę, że to pozwoli Ci osiągnąć swój cel.

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
 2
Author: Mitselplik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-15 16:27:13

Problem polega na tym, że wskazujesz na wartość znajdującą się na stosie i nie będzie ona przenoszona z powrotem do właściwości orignal, więc C# nie pozwala zwracać referencji do typu wartości. Myślę, że możesz to rozwiązać usuwając właściwość Origin i zamiast tego użyć publicznego pliku, tak Wiem, że nie jest to miłe rozwiązanie. Innym rozwiązaniem jest nie używać punktu, a zamiast tego utworzyć własny typ punktu jako obiekt.

 0
Author: Fredrik Normén,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-17 09:54:45

Myślę, że haczyk polega na tym, że próbujesz przypisać podrzędne wartości obiektu w instrukcji, zamiast przypisywać sam obiekt. W tym przypadku należy przypisać cały obiekt Point jako typ właściwości Point.

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

Hope I made sense there

 0
Author: MSIL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-25 07:38:51

Po prostu usuń właściwość "get set" w następujący sposób, a potem wszystko działa jak zawsze.

W przypadku typów prymitywnych instread użyj get; set;...

using Microsoft.Xna.Framework;
using System;

namespace DL
{
    [Serializable()]
    public class CameraProperty
    {
        #region [READONLY PROPERTIES]
        public static readonly string CameraPropertyVersion = "v1.00";
        #endregion [READONLY PROPERTIES]


        /// <summary>
        /// CONSTRUCTOR
        /// </summary>
        public CameraProperty() {
            // INIT
            Scrolling               = 0f;
            CameraPos               = new Vector2(0f, 0f);
        }
        #region [PROPERTIES]   

        /// <summary>
        /// Scrolling
        /// </summary>
        public float Scrolling { get; set; }

        /// <summary>
        /// Position of the camera
        /// </summary>
        public Vector2 CameraPos;
        // instead of: public Vector2 CameraPos { get; set; }

        #endregion [PROPERTIES]

    }
}      
 0
Author: Roberto Mutti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-13 08:04:43

Myślę, że wiele osób się tutaj myli, ten szczególny problem jest związany ze zrozumieniem, że właściwości typu wartości zwracają kopię typu wartości (tak jak w przypadku metod i indekserów), a pola typu wartości są dostępne bezpośrednio. Poniższy kod robi dokładnie to, co próbujesz osiągnąć, uzyskując bezpośredni dostęp do pola zapasowego właściwości (Uwaga: wyrażenie właściwości w jej wyrazistej formie z polem zapasowym jest odpowiednikiem właściwości auto, ale ma tę zaletę, że w naszym kodzie możemy uzyskać bezpośredni dostęp do zaplecza):

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass();
        myClass.SetOrigin();
        Debug.Assert(myClass.Origin.X == 10); //succeeds
    }
}

class MyClass
{
    private Point _origin;
    public Point Origin
    { 
        get => _origin; 
        set => _origin = value; 
    }

    public void SetOrigin()
    {
        _origin.X = 10; //this works
        //Origin.X = 10; // fails with CS1612;
    }
}

Błąd, który otrzymujesz, jest pośrednią konsekwencją nie zrozumienia, że właściwość zwraca kopię typu wartości. Jeśli zostanie zwrócona Kopia typu wartości i nie przypiszesz jej do zmiennej lokalnej, to wszelkie zmiany wprowadzone w tej kopii nigdy nie zostaną odczytane i dlatego kompilator zgłosi to jako błąd, ponieważ nie może to być zamierzone. Jeśli przypiszemy kopię do zmiennej lokalnej wtedy możemy zmienić wartość X, ale będzie ona zmieniana tylko na lokalnej kopii, co naprawia błąd czasu kompilacji, ale nie będzie miało pożądanego efektu modyfikowania właściwości Origin. Poniższy kod ilustruje to, ponieważ błąd kompilacji zniknął, ale twierdzenie debug nie powiedzie się:

class Program
{
    static void Main(string[] args)
    {
        var myClass = new MyClass();
        myClass.SetOrigin();
        Debug.Assert(myClass.Origin.X == 10); //throws error
    }
}

class MyClass
{
    private Point _origin;
    public Point Origin
    { 
        get => _origin; 
        set => _origin = value; 
    }

    public void SetOrigin()
    {
        var origin = Origin;
        origin.X = 10; //this is only changing the value of the local copy
    }
}
 0
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-01 18:42:23