2016-06-18 2 views
1

Я совершенно новичок в C#, и я все еще разбираюсь. Моя проблема заключается в том, что у меня есть класс, как это:C# - Как я могу изменить структуру, заданную геттером?

class Sprite { 
    private Vector3 _position; 

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

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

С объектом Vector3 и/набором блоком ГЕТ. Вот упрощенная версия структуры Vector3:

struct Vector3 { 
    float X, Y, Z; 
} 

Теперь моя проблема заключается в том, что если я это сделать:

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

Это дает мне ошибку, потому что позиция не является переменной, но дано мне геттером. Но я не хочу публиковать _position, потому что я хочу обработать событие, когда переменная изменена.

(В Java это работает отлично, поэтому я запутался: /)

Не могли бы вы дать мне намек, что я делаю неправильно или что вы могли бы сделать по-другому?

Edit:

Да, Vector3 является структурой, а не класс. Извините за путаницу, но я довольно новичок в C#.

+2

Можете ли вы разместить сообщение об ошибке, пожалуйста? Это должно сработать. – nvoigt

+4

Вы уверены, что Vector3 - это класс, а не структура? –

+0

Не видите ничего плохого в опубликованном коде. Должно быть что-то еще, что вы не разместили. – Rahul

ответ

3

(In Java this works perfectly, that's why I'm confused :/)

У Java нет того, что называет C# struct.

В C# struct создает value type.Когда вы возвращаете тип значения из свойства getter, вы не возвращаете ссылку на уже существующий объект где-то, вы возвращаете совершенно новую копию значения. И из-за этого, нет смысла модифицировать эту копию значения: никто не увидит изменения.

В Java вы должны использовать для этого class. В C# вы можете сделать то же самое. Это создает ссылочный тип. Когда вы возвращаете ссылочный тип из свойства getter, вы не возвращаете копию всех полей объекта, вы просто возвращаете ссылку на тот же объект. Здесь изменения имеют смысл. У вас есть несколько ссылок на один и тот же объект, и изменения все еще видны через любую из других ссылок.

+0

Спасибо за объяснение. Это определенно помогает мне :) – RagingRabbit

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

Как ваш вектор представляется структура, поскольку структура является значение типа (что означает, что ваш поглотитель, который называется будет возвращать копии вашей позиции), вы не можете работать на что возвращает ваш геттер. Вам нужно будет создать новый Вектор и назначить его в целом. Обратите внимание, что это, по-видимому, оптимизированный человек, созданный для вас. Если определение объекта Vector принадлежит вам, просто сделайте его классом, чтобы он работал так, как вы привыкли к Java.

Если вы хотите это быть-структуру, вам придется создать новую и присвоить его:

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

Спасибо, что указали это, я отредактировал вопрос. Я довольно новичок в C#, так что извините за путаницу. – RagingRabbit

0

Попробуйте это:

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

Причина ошибки:

Проблема заключается в том, что sprite.Position возвращает структуру, поэтому при ее доступе она создает копию из-за семантики значения. + = пытается изменить это значение, но оно будет изменять временную копию, а не фактическую структуру, хранящуюся в вашем sprite.

Вам нужно принять значение, прочитав позицию и поместив ее в локальную переменную, измените эту локальную переменную, а затем верните локальную переменную в позицию.

+0

Спасибо за пример. – RagingRabbit

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, поскольку она не имеет структур вообще.

Смежные вопросы