错误:“无法修改返回值”时间:2019-03-17 标签:c#

发布于 2024-08-12 06:01:49 字数 327 浏览 6 评论 0原文

我正在使用自动实现的属性。 我想解决以下问题的最快方法是声明我自己的支持变量?

public Point Origin { get; set; }

Origin.X = 10; // fails with CS1612

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

尝试修改值类型,该值类型是 中间表达。因为该值没有被持久化,所以该值 将保持不变。

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

I'm using auto-implemented properties.
I guess the fastest way to fix following is to declare my own backing variable?

public Point Origin { get; set; }

Origin.X = 10; // fails with CS1612

Error Message: Cannot modify the return value of 'expression' because
it is not a variable

An attempt was made to modify a value type that was the result of an
intermediate expression. Because the value is not persisted, the value
will be unchanged.

To resolve this error, store the result of the expression in an
intermediate value, or use a reference type for the intermediate
expression.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

巨坚强 2024-08-19 06:01:50

只需按如下方式删除属性“get set”,然后一切都会像往常一样工作。

对于基本类型,请使用 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]

    }
}      

Just remove the property "get set" as follow, and then everything works as always.

In case of primitive types instread use the 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]

    }
}      
々眼睛长脚气 2024-08-19 06:01:49

这是因为 Point 是一种值类型 (struct)。

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

如果您只想更改 X 值,则需要执行以下操作:

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

This is because Point is a value type (struct).

Because of this, when you access the Origin property you're accessing a copy of the value held by the class, not the value itself as you would with a reference type (class), so if you set the X property on it then you're setting the property on the copy and then discarding it, leaving the original value unchanged. This probably isn't what you intended, which is why the compiler is warning you about it.

If you want to change just the X value, you need to do something like this:

Origin = new Point(10, Origin.Y);
々眼睛长脚气 2024-08-19 06:01:49

使用支持变量不会有帮助。 Point 类型是值类型。

您需要将整个 Point 值分配给 Origin 属性: -

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

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

即使您使用自己的支持变量,您的 get 也会如下所示: -

get { return myOrigin; }

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

嗯...更仔细地阅读了您的问题后,也许您实际上是想直接从类中修改支持变量:-

myOrigin.X = 10;

是的,这就是您所需要的。

Using a backing variable won't help. The Point type is a Value type.

You need to assign the whole Point value to the Origin property:-

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

The problem is that when you access the Origin property what is returned by the get is a copy of the Point structure in the Origin properties auto-created field. Hence your modification of the X field this copy would not affect the underlying field. The compiler detects this and gives you an error since this operation is entirely useless.

Even if you used your own backing variable your get would look like:-

get { return myOrigin; }

You'd still be returning a copy of the Point structure and you'd get the same error.

Hmm... having read your question more carefully perhaps you actually mean to modify the backing variable directly from within your class:-

myOrigin.X = 10;

Yes that would be what you would need.

话少心凉 2024-08-19 06:01:49

现在您已经知道错误的根源是什么。如果不存在带有重载的构造函数来获取您的属性(在本例中为 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;

这看起来是一件非常奇怪的事情,根本不推荐。只是列出一种替代方法。更好的方法是使结构不可变并提供适当的构造函数。

By now you already know what the source of the error is. In case a constructor doesn't exist with an overload to take your property (in this case X), you can use the object initializer (which will do all the magic behind the scenes). Not that you need not make your structs immutable, but just giving additional info:

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.

This is possible because behind the scenes this happens:

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

This looks like a very odd thing to do, not at all recommended. Just listing an alternate way. The better way to do is make struct immutable and provide a proper constructor.

沉溺在你眼里的海 2024-08-19 06:01:49

我认为很多人在这里感到困惑,这个特定问题与理解值类型属性返回值类型的副本(与方法和索引器一样)和值类型有关字段可直接访问。以下代码正是通过直接访问属性的支持字段来实现您想要实现的目标(注意:使用支持字段以其详细形式表达属性相当于自动属性,但优点是在我们的代码中我们可以直接访问支持字段):

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

I think a lot of people are getting confused here, this particular issue is related to understanding that value type properties return a copy of the value type (as with methods and indexers), and value type fields are accessed directly. The following code does exactly what you are trying to achieve by accessing the property's backing field directly (note: expressing a property in its verbose form with a backing field is the equivalent of an auto property, but has the advantage that in our code we can access the backing field directly):

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

The error you are getting is an indirect consequence of not understanding that a property returns a copy of a value type. If you are returned a copy of a value type and you do not assign it to a local variable then any changes you make to that copy can never be read and therefore the compiler raises this as an error since this cannot be intentional. If we do assign the copy to a local variable then we can change the value of X, but it will only be changed on the local copy, which fixes the compile time error, but will not have the desired effect of modifiying the Origin property. The following code illustrates this, since the compilation error is gone, but the debug assertion will fail:

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
    }
}
薄情伤 2024-08-19 06:01:49

除了争论结构与类的优缺点之外,我倾向于从这个角度看待目标并解决问题。

话虽这么说,如果您不需要在属性 get 和 set 方法后面编写代码(如您的示例中所示),那么简单地将 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

Aside from debating the pros and cons of structs versus classes, I tend to look at the goal and approach the problem from that perspective.

That being said, if you don't need to write code behind the property get and set methods (as in your example), then would it not be easier to simply declare the Origin as a field of the class rather than a property? I should think this would allow you to accomplish your goal.

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
小嗲 2024-08-19 06:01:49

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

The problem is that you point to a value located on the stack and the value will not be relfected back to the orignal property so C# does not allow you to return a reference to a value type. I think you can solve this by removing the Origin property and instead use a public filed, yes I know it's not a nice solution. The other solution is to not use the Point, and instead create your own Point type as an object.

千纸鹤 2024-08-19 06:01:49

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

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

希望我在那里说得通

I guess the catch here is that you are trying to assign object's sub-values in the statement rather than assigning the object itself. You need to assign the entire Point object in this case as the property type is Point.

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

Hope I made sense there

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文