简体   繁体   English

C#-如何修改由吸气剂给定的结构?

[英]C# - How can I modify a struct given by a getter?

I'm quite new to C# and I'm still figuring things out. 我对C#还是很陌生,但仍在弄清楚。 My problem is that I've got a class like this: 我的问题是我上了这样的课:

class Sprite {
    private Vector3 _position;

    public Vector3 Position {
        get { return _position; }
        set { _position = value;
              HandleEvent(); }
    }

    public Sprite() {
        _position = new Vector3();
    }
}

With a Vector3 object and a get/set block. 带有一个Vector3对象和一个get / set块。 Here is a simplified version of the Vector3 struct: 这是Vector3结构的简化版本:

struct Vector3 {
    float X, Y, Z;
}

Now my problem is that if I do this: 现在我的问题是,如果我这样做:

Sprite sprite = new Sprite();
sprite.Position.X += 4.0F;

It gives me an error because Position is not a variable but given to me by a getter. 这给我一个错误,因为Position不是变量,而是由getter给我的。 But I don't want to make _position public, because I want to handle an event when the variable is changed. 但是我不想公开_position,因为我想在变量更改时处理一个事件。

(In Java this works perfectly, that's why I'm confused :/) (在Java中,这非常有效,这就是为什么我感到困惑的原因:/)

Could you give me a hint what I'm doing wrong or what you would do differently? 您能给我一个提示吗,我做错了什么,或者您会做些什么?

Edit: 编辑:

Yes, Vector3 is a struct and not a class. 是的,Vector3是一个结构而不是一个类。 Sorry for the confusion, but I'm pretty new to C#. 抱歉给您带来混乱,但是我对C#还是很陌生。

(In Java this works perfectly, that's why I'm confused :/) (在Java中,这非常有效,这就是为什么我感到困惑的原因:/)

Java does not have what C# calls struct . Java没有C#所谓的struct

In C#, struct creates a value type . 在C#中, struct创建一个值类型 When you return a value type from a property getter, you don't return a reference to an already existing object somewhere, you return a brand new copy of the value. 从属性获取器返回值类型时,不会在某个地方返回对现有对象的引用,而会返回该值的全新副本。 And because of that, it does not make sense to modify that copy of the value: no one would see the modification. 因此,修改该值的副本没有任何意义:没人会看到该修改。

In Java, you would use class for this. 在Java中,您将为此使用class In C#, you can do the same. 在C#中,您可以执行相同的操作。 That creates a reference type. 这将创建一个引用类型。 When you return a reference type from a property getter, you don't return a copy of all of the object's fields, you just return a reference to the same object. 当从属性获取器返回引用类型时,您不会返回该对象所有字段的副本,而只是返回对同一对象的引用。 Here, modifications do make sense. 在这里,修改确实有意义。 You have multiple references to the same object, and the modifications are still visible through any of the other references. 您具有对同一对象的多个引用,并且通过其他任何引用仍然可以看到修改。

It should work fine. 应该工作正常。 This sample compiles: 该示例编译:

namespace ConsoleApplication8
{
    class Sprite
    {
        private Vector3 _position;

        public Vector3 Position
        {
            get { return _position; }
            set
            {
                _position = value;
                // HandleEvent();
            }
        }

        public Sprite()
        {
            _position = new Vector3();
        }
    }

    class Vector3
    {
        public float X, Y, Z;
    }

    class Program
    {
        static void Main()
        {
            Sprite sprite = new Sprite();

            sprite.Position.X += 4.0F;
        }
    }
}

As your vector seems to be a struct, because a struct is a value-type (which means your getter that is called will return a copy of your position) you cannot operate on what your getter returns. 由于向量似乎是一个结构,因为结构是一种值类型(这意味着被调用的getter将返回您位置的副本 ),因此您无法对getter返回的内容进行操作。 You will need to make a new Vector and assign that one as a whole. 您将需要制作一个新的Vector并将其整体分配。 Please note that this seems to be an optimization somebody made for you. 请注意,这似乎是某人为您进行的优化 If the Vector object definition belongs to you, just make it a class so it works like you are used to from Java. 如果Vector对象定义属于您,只需将其设为一个类,使其像您从Java习惯的那样工作。

If you want this to be a struct, you will have to create a new one and assign it: 如果使其成为一个结构,则必须创建一个新结构并为其分配:

            sprite.Position = new Vector 
                              {
                                  X = sprite.Position.X + 4.0F,
                                  Y = sprite.Position.Y,
                                  Z = sprite.Position.Z
                              };

Because Vector3 is a struct, it gets copied around implicitly. 因为Vector3是一个结构,所以它被隐式复制。 For example, the following code creates two vectors, instead of one: 例如,以下代码创建两个向量,而不是一个:

Vector3 tmp1 = new Vector3();
Vector3 tmp2 = tmp1;

This can be confusing if you're mostly used to classes, where an instance is not copied and not created unless you explicitly say so (using new , for example). 如果您最习惯使用类,除非您明确声明(例如,使用new ,否则不会复制和创建实例,这可能会造成混淆。

Combine the above with the fact that C# properties are syntactic sugar for methods, and you'll have your answer. 将以上内容与C#属性是方法的语法糖这一事实结合起来,您将得到答案。 This: 这个:

Sprite sprite = new Sprite();
sprite.Position.X += 4.0F;

Is seen like this: 看起来像这样:

Sprite sprite = new Sprite();
sprite.get_Position().X += 4.0F;

Which would be executed like this: 可以这样执行:

Sprite sprite = new Sprite();
Vector3 tmp1 = sprite.get_Position();
tmp1.X += 4.0F;

Notice that tmp1 is a brand new Vector3 . 请注意, tmp1是全新的Vector3 It's unrelated to sprite.Position in every way, except for the fact that they contained equal coordinates at some point. 它与sprite.Position无关,除了它们在某个点包含相等的坐标外。

Changing that temporary Vector3 won't have an effect on the Vector3 returned by the property. 更改该临时Vector3不会影响该属性返回的Vector3 The C# compiler is aware of this unfortunate pattern and refuses to compile it because it's almost certainly not what you want. C#编译器意识到这种不幸的模式,并拒绝编译它,因为几乎可以肯定这不是您想要的。

To work around this, you can try taking the position explicitly, like above, and then explicitly put it back: 要解决此问题,您可以尝试像上面一样明确地占据该位置,然后将其明确放回去:

Sprite sprite = new Sprite();
Vector3 tmp1 = sprite.Position;
tmp1.X += 4.0F;
sprite.Position = tmp1;

In general, you should avoid mutable structs for reasons like this. 通常,出于这种原因,应避免使用可变结构。


Java doesn't have this problem because it doesn't have structs at all. Java没有这个问题,因为它根本没有结构。

Try this: 尝试这个:

 Sprite sprite = new Sprite();
        Vector3 v = sprite.Position;
        v.X += 0.4F;
        sprite.Position = v;

Cause of Error: 错误原因:

The problem is that sprite.Position returns a struct, so when you access it, it creates a copy of it due to the value semantics. 问题是sprite.Position返回一个结构,因此当您访问它时,由于值语义的缘故,它会创建它的一个副本。 += attempts to modify that value, but it'll be modifying a temporary copy - not the actual struct stored in your sprite . + =试图修改该值,但它将修改一个临时副本-而不是存储在您的sprite的实际结构。

You have to take the value from reading the Position and put it into a local variable, change that local variable, and then assign the local variable back into Position. 您必须从读取Position中获取值并将其放入局部变量,更改该局部变量,然后将局部变量分配回Position中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM