C# Properties

Started by
7 comments, last by jpetrie 16 years, 6 months ago
I'm using a public property for allowing objects to modify the Vector3 position of another object. This works fine, but changing the position with the property is becoming tedious as I cannot change the sub members of the Vector3 variable directly through the property. For example:
public Vector3 Position
{
   get { return m_position; }
   set { m_position = value; }
}

class Test
{
   void Foo()
   {
      Object.Position.X += 4;    // I can't do this

      Object.Position += new Vector3(0, 4, 0);    // I must do this
   }
}

It's tiresome to create new vectors everytime i need to hardcode some movement and this also applies to rotation and scaling. Is there a work around for this? Also, it's necessary for me to use properties as I will need to add addition instructions later for whenever the property is modified.
If it's possible for us to conceive it, than it must be possible.
Advertisement
This:
Object.Position += new Vector3(0, 4, 0);

won't work either for the same reason as the line before it. You'll be adding to a copy of the value in Object, not the value in Object.

There are two types of object: value types and reference types. The difference is that value types are passed by value (i.e. a copy is made of the object) whereas reference types all refer to the same object (i.e. no copy of the object is made). In C# 'struct' denotes a value type and 'class' denotes a reference type.

I'm guessing that Vector3 is a 'struct'.

You have three options. The first is to make Vector3 a reference type. There are quite a few issues to this and probably not the best solution.

The second solution is to not use the += operator, but instead use the following:
Object.Position = Object.Position + new Vector3(0, 4, 0);

but that too is a bit icky. Anyone looking at that will wonder why += wasn't used.

The last and best solution is to design the class better:
public Vector3 Position // a read only property{   get { return m_position; }}public void Move (Vector3 delta){   m_position += delta;}public void Move (float dx, float dy, float dz){   // here, x,y,z are public members of Vector3 and not properties   m_position.x += dx;   m_position.y += dy;   m_position.z += dz;}

This will lead to easier to understand code:
Object.Move (0, 4, 0); // the object is being moved, can't possibly misunderstand this

If you have a property of the form:
public some_type SomeProperty{   get { return m_some_member; }   set { m_some_member = value; }}

then there's no reason to use the property syntax. The property syntax is used to make complex operations look like member variables or to restrict access to members.

For game objects, this makes more sense:
public Vector3 Position{   get { return m_position; }   // no setter function}public void Move (Vector3 delta) // as above

which then prevents objects from being randomly positioned within the game world and enforces the Move concept which could perform collision detection when moving (so objects don't go through walls for example). The initial position of the object would be specified in the constructor.

Skizz
Well, the point of having a variable private and a property public is to hide implementation, not the actual variable. Your current set-up is exactly like having a public variable. But obviously you think that's wrong, so you've made it private and put an identical (albeit limited) replacement up there. So... make your variable Position and make it public.

When it comes to things like this, you have to think about behaviour, not "public variables are teh devil". For example, if it's correct for other classes/functions to modify the position (and it clearly is), by either setting is absolutely or "+="-ing it, then just let it be public. If it was wrong for one of these things to happen - say, setting its position absolutely, then hiding the variable and making a move function would be the correct thing to do. But in this instance, hiding the variable and writing functions that effectively "un-hide" the variable (a += function, a = function, a get function) is, well... silly.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]
Quote:Original post by Skizz
This:
Object.Position += new Vector3(0, 4, 0);

won't work either for the same reason as the line before it. You'll be adding to a copy of the value in Object, not the value in Object.


That's incorrect. That code you posted will work just fine. I do it all the time in my code. The expression

Object.Position += new Vector3(0, 4, 0);

just expands to

Object.Position = Object.Position + new Vector3(0, 4, 0);

when compiled. So you might as well save yourself the trouble and let the compiler do the work for you.


Needless to say the rest of your post, while it will work, is a long way around a problem that doesn't exist.



To the OP: It does suck that you can't access the fields of the property, but that has to do with encapsulation in C# I believe. You either have to do it the long way like you discovered or make properties for each piece like so:

class Object{   Vector3 position;   public float PositionX   {       get { return position.X; }       set { position.X = value; }   }}


Not very clean, but the best way if you want to modify the fields easily.
Quote:Original post by Skizz
If you have a property of the form:
public some_type SomeProperty{   get { return m_some_member; }   set { m_some_member = value; }}

then there's no reason to use the property syntax. The property syntax is used to make complex operations look like member variables or to restrict access to members.


(wanted to respond to this as well)

There are reasons for this. The first of which being that you could later add a restriction to your property without breaking the interface. The overhead of a property is so miniscule if you are just using it like above (and may even get inlined by the compiler) that I personally feel it's worth using properties for consistency and future extendibility.

Also keep in mind that properties are not for complex operations. The standard states that properties are supposed to be small and lightweight. You should only have a few operations inside of a property. If you have a large, complex property, you should definitely want a method. (Well, if you want to conform to the guidelines of the standard).
Quote:
There are reasons for this. The first of which being that you could later add a restriction to your property without breaking the interface.

I'm unclear what aspect of "interface" you're referring to here.
public T Foo;

can be trivially changed to
public T Foo{  get { ... }  set { ... } }

without breaking any code that refers to Foo (it will of course require a new assembly, but so will any change). It will break reflection code that specifically enumerates the fields or properties of the class... although it may still be possible to write the reflection code in such a way as to be fault tolerant and still contextually correct (e.g., look for both).

Is there some other aspect of "interface" you're thinking of?

I tend to prefer making fields directly public like this (in C#), because it's slightly less work for me to type... not for any silly performance reasons.
Yeah, I suppose that is true.

So I guess all I'm left with is it saves me work later should I want to switch to a property because I don't have to type as much. :)

I always prefer properties because I like knowing at any point I can change some restrictions on the variable or other minor things. Also, even in the case of the most basic get/set, I always see properties as the object allowing you to see the field where as a public field seems more like you just taking the object's data. I guess it seems more OO in my eyes and I'm all for making things more OO when it isn't much trouble.
It would be nice if I could do something like this:

public float Vector3.X{   get { return m_vector3.X; }   set { m_vector3.X = value; }}


But I suppose that would be pretty tedious as well. Guess I'll just have to keep doing what I'm doing.
If it's possible for us to conceive it, than it must be possible.
What would be the point? Put the property in the vector class itself.

The only way your example makes any sense from a sane interface design standpoint is if that vector is entirely hidden from the user (in which case, you can do what you want via the abstraction layer in your class that is hiding that vector). What you've posted there directly allows you to manipulate and change the observed behavior of class B from class A -- this is a Bad Idea.

Now, if you only want this to ease the "pain" of (for example) modifying properties of properties that are value types, then the problem there is because Vector3 is a value type, and the return value of the property is a copy, not the object itself (properties are really functions, the property public T Foo { get; set; } generates functions T get_Foo(){} and void set_Foo(T t){} -- try to create one of those functions and you'll see the compiler tell you about it). Make the type a reference type (not really sane for vectors though), or expose a method to do what you want. For example, for a camera class you might have the Position property and a DisplaceBy(x,y,z) method. This avoids the "create new vectors" issue (which isn't really a huge problem, it's not like it's a whole lot more typing, especially with Intellisense and/or ReSharper), and it provides a solution without having to resort to the pathologically design-breaking feature you originally suggested.

This topic is closed to new replies.

Advertisement