代码之家  ›  专栏  ›  技术社区  ›  P a u l

无法修改返回值错误c#

  •  113
  • P a u l  · 技术社区  · 16 年前

    我正在使用自动实现的属性。

    public Point Origin { get; set; }
    
    Origin.X = 10; // fails with CS1612
    

    错误消息:无法修改“表达式”的返回值,因为 它不是一个变量

    试图修改由错误导致的值类型

    若要解决此错误,请将表达式的结果存储在 中间值,或使用中间值的引用类型

    6 回复  |  直到 6 年前
        1
  •  218
  •   Greg Beech    16 年前

    这是因为 Point struct ).

    因此,当您访问 Origin 类所持有的值,而不是引用类型中的值本身( class ),因此,如果设置 X 属性,然后在副本上设置属性,然后丢弃它,保持原始值不变。这可能不是您想要的,这就是编译器警告您的原因。

    如果你想改变的话 X 值,您需要执行以下操作:

    Origin = new Point(10, Origin.Y);
    
        2
  •  11
  •   Flot2011    12 年前

    使用支持变量没有帮助。 Point 类型是一种值类型。

    您需要将整个点值指定给原点特性:-

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

    问题是当您访问Origin属性时 get 是“原点特性自动创建”字段中点结构的副本。因此,修改此副本的X字段不会影响基础字段。编译器会检测到这一点,并给出一个错误,因为此操作完全无用。

    即使您使用自己的支持变量 得到

    get { return myOrigin; }
    

    您仍然会返回点结构的副本,并且会得到相同的错误。

    隐马尔可夫模型。。。仔细阅读您的问题后,您可能实际上想直接在类中修改支持变量:-

    myOrigin.X = 10;
    

    是的,那正是你需要的。

        3
  •  7
  •   neonblitzer MakePeaceGreatAgain    10 年前

    到现在为止,您已经知道错误的来源。如果构造函数不存在,则重载将获取您的属性(在本例中 X ),您可以使用对象初始值设定项(它将在幕后发挥所有作用)。 并不是说你不需要使你的结构不可变 ,但仅提供附加信息:

    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.
    

    这是可能的,因为在幕后会发生这种情况:

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

    一点也不推荐。只是列出另一种方法。更好的方法是使结构不可变并提供适当的构造函数。

        4
  •  2
  •   Mitselplik    7 年前

    除了讨论结构和类的利弊之外,我倾向于从这个角度看待目标和解决问题。

    Origin 作为类的字段而不是属性?我想这会让你实现你的目标。

    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
    
        5
  •  0
  •   Fredrik Normén    16 年前

    问题是您指向堆栈上的一个值,该值不会重新影响到原始属性,因此C#不允许您返回对值类型的引用。我认为您可以通过删除Origin属性来解决这个问题,而是使用公共字段,是的,我知道这不是一个好的解决方案。另一种解决方案是不使用点,而是创建自己的点类型作为对象。

        6
  •  0
  •   nawfal Donny V.    13 年前

    我想这里的问题是您试图在语句中分配对象的子值,而不是分配对象本身。在这种情况下,需要指定整个点对象,因为特性类型为点。

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

    希望我在那里讲得通

        7
  •  0
  •   Roberto Mutti    6 年前

    只需删除属性“getset”,如下所示,然后一切照常工作。

    如果是基元类型instread,则使用get;设置

    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]
    
        }
    }      
    
        8
  •  0
  •   Matt    6 年前

    我想很多人都感到困惑, 这一特殊问题与理解该值类型有关 性质 返回值类型(与方法和索引器一样)和值类型的副本 领域 . 下面的代码正是通过直接访问属性的支持字段来实现的(注意:用支持字段以详细形式表示属性等同于自动属性,但其优点是,在我们的代码中,我们可以直接访问支持字段):

    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;
        }
    }
    

    您得到的错误是不理解属性返回值类型副本的间接结果。如果返回值类型的副本,并且未将其分配给局部变量,则无法读取对该副本所做的任何更改,因此编译器将此作为错误,因为这不是故意的。如果将副本指定给局部变量,则可以更改X的值,但它只会在局部副本上更改,这会修复编译时错误,但不会达到修改Origin属性的预期效果。以下代码说明了这一点,因为编译错误已消失,但调试断言将失败:

    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
        }
    }