C# - 如何修改getter给出的结构?

时间:2016-06-18 15:13:45

标签: c# getter

我对C#很陌生,我还在搞清楚事情。 我的问题是我有一个这样的课程:

class Sprite {
    private Vector3 _position;

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

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

使用Vector3对象和get / set块。 这是Vector3结构的简化版本:

struct Vector3 {
    float X, Y, Z;
}

现在我的问题是,如果我这样做:

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

它给了我一个错误,因为位置不是变量,而是由吸气剂给我。但我不想公开_position,因为我想在变量发生变化时处理事件。

(在Java中,这非常有效,这就是为什么我感到困惑:/)

你可以给我一个暗示我做错了什么或你会做些什么不同的事情?

修改

是的,Vector3是一个结构而不是一个类。很抱歉这个混乱,但我对C#很新。

4 个答案:

答案 0 :(得分:3)

  

(在Java中,这非常有效,这就是为什么我感到困惑:/)

Java没有C#调用struct

在C#中,struct会创建value type。当您从属性getter返回值类型时,您不会在某处返回对已存在对象的引用,而是返回该值的全新副本。因此,修改该值的副本是没有意义的:没有人会看到修改。

在Java中,您可以使用class。在C#中,您也可以这样做。这会创建一个引用类型。当您从属性getter返回引用类型时,您不会返回所有对象字段的副本,只需返回对同一对象的引用。在这里,修改确实有意义。您有多个对同一对象的引用,并且通过任何其他引用仍可以看到修改。

答案 1 :(得分:1)

应该正常工作。该示例编译:

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

由于你的向量似乎是一个结构,因为结构是一个值类型(这意味着你的被调用的getter将返回你职位的副本)你无法操作你的getter回报。您需要创建一个新的Vector并将其作为一个整体分配。请注意,这似乎是为您制作的优化。如果Vector对象定义属于您,只需将其设为一个类,这样它就像您习惯使用Java一样。

如果想要这是一个结构,你必须创建一个新结构并分配它:

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

答案 2 :(得分:1)

因为Vector3是一个结构,所以它会被隐式复制。例如,以下代码创建两个向量,而不是一个:

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

如果您主要习惯于没有复制并且未创建实例的类,除非您明确说明(例如,使用new),否则这可能会造成混淆。

将上述内容与C#属性作为方法的语法糖这一事实相结合,您将得到答案。这样:

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

就像这样:

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

将执行以下操作:

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

请注意tmp1是一个全新的Vector3。它在各个方面与sprite.Position无关,除了它们在某些点上包含相等坐标的事实。

更改该临时Vector3不会对该属性返回的Vector3产生影响。 C#编译器意识到这种不幸的模式,并拒绝编译它,因为它几乎肯定不是你想要的。

要解决这个问题,你可以尝试明确地采取这个位置,就像上面一样,然后明确地把它放回去:

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

一般来说,出于这样的原因,你应该避免使用可变结构。

Java没有这个问题,因为它根本没有结构。

答案 3 :(得分:0)

试试这个:

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

错误原因:

问题是sprite.Position返回一个结构,所以当你访问它时,它会因值语义而创建它的副本。 + =尝试修改该值,但它将修改临时副本 - 而不是存储在sprite中的实际结构。

您必须从读取位置获取值并将其放入局部变量,更改该局部变量,然后将局部变量分配回位置。