views:

432

answers:

4

Say i have a property in a class:

Vector3 position{get; set;}

So i create an instance of that class somewhere and now i want to change position.x, that would be impossible now because the getter and setter set and get the whole object. So i have to make a temporary Vector3 change its values and then assign it.

Normally i would make position a public field so that problem would be solved. But i cant do it in this case because position is an implementation of an interface and interfaces cant have fields.

So how can i solve this the best way.

Edit: Vector3 is a struct so its a value type

+2  A: 

That's one of the issues with mutable value types. You can create a new instance of the value type with the new X value and reassign in to the property. You can make the instance creation easier by providing useful constructors or adding methods that return a modified object (instead of modifying the value).

Mehrdad Afshari
The problem is that position will be changed allot. So creating a new instance or calling a method every time i want to modify the property would be overkill.
slayerIQ
@slayerIQ: You can't modify this in the interface. Either you'll have to make `Vector3` a class (which is probably less than ideal) or provide methods that modify position in the interface (with things like `MoveHorizontally(float distance)`) or just have the clients assign the property like `obj.Position = new Vector3(obj.Position.X + 10, obj.Position.Y, obj.Position.Z);`. This problem doesn't really have a better solution (the canonical example is Windows Forms with the `Location` and `Size` properties of the `Control` class).
Mehrdad Afshari
slayerIQ never said that Vector3 is a value type. In fact, the post says it is a class. Whether that's a typo or not isn't clear.
Eilon
@Eilon: If `Vector3` was a reference type, you could easily do `obj.Position.X += 10;` without any issues and you wouldn't have any issues.
Mehrdad Afshari
Right, but it isn't clear to me that slayerIQ actually tried that (or knew it was possible). I don't see any mention of compilation errors or runtime errors.
Eilon
Vector3 is a struct, Sorry for not specifying that in the question.
slayerIQ
Well that settles that :)
Eilon
I assume it is indeed a struct - this struct: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector3.aspx; sorry @Mehrdad, I would upvote but I'm all out for today.
Marc Gravell
@Marc: Don't worry. I'm above the cap ;)
Mehrdad Afshari
Eilon, you didn't read carefully. He said this is a property in a class. He didn't say `Vector3` is itself a class.
Kyralessa
@Kyralessa, good point. I misinterpreted the "that" to mean `Vector3` and not the containing class.
Eilon
+5  A: 

IMO, the easiest answer here:

private Vector3 position;
public Vector3 Position {
    get {return position;}
    set {position = value;} // with @Mehrdad's optimisation
}
public float X {
    get {return position.X;}
    set {position.X = value;}
}
public float Y {
    get {return position.Y;}
    set {position.Y = value;}
}
public float Z {
    get {return position.Z;}
    set {position.Z = value;}
}

Now you can change obj.X, obj.Y and obj.Z if you only need to change one dimension, or change obj.Position to change everything.

If you need the name position to implement an interface, then do it explicitly:

Vector3 IWhateverInterface.position {
    get {return position;}
    set {position = value;}
}
Marc Gravell
Yes thats what i thought about but like i explained in the comments above position will be modified allot so is this the most efficient way? Reading the answers i assume this is the only way am i right ?
slayerIQ
This is essentially identical to providing methods. A possible micro-optimization is to avoid using automatic properties for `Position` and directly modify `position.X` in the `X` property.
Mehrdad Afshari
@slayerIQ you have to pick your battle. If that is the problem you *could* just expose `position` as the field, and do the explicit interface implementation as per the bit I added at the end?
Marc Gravell
Thanks i'll go with the explicit interface implementation of position :)
slayerIQ
@Mehrdad you are correct. It is late... modified (with credit)
Marc Gravell
A: 

Pre-P.S.: Saw too late that Vector3 is a value type; the following post therefore won't be of much help. Sorry for that mistake.

Well, while interfaces cannot have fields, they can have properties, e.g.:

interface IVector3
{
    double X { get; set; }
    double Y { get; set; }
    double Z { get; set; }
}

In your Vector3, you simply implement those like everything else:

class Vector3 : IVector3
{
    double IVector3.X
    {
        get { ... }
        set { ... } 
    }
    ...
}

Now back to your position property. You tie the property to a fixed instance during initialization and only provide a getter:

Vector3 position
{
    get
    {
        return _position;
    }
}

private Vector3 _position = new Vector3(...);

By making the property read-only (ie. no setter), you ensure that it won't be replaced with a new Vector3 object. Instead, you tie it to a fixed instance (_position) at initialization time. But you can change the Vector3 by assigning new values to position.X, position.Y, or position.Z.

stakx
+5  A: 

Is the straightforward solution somehow not acceptable?

foo.position = new Vector(newX, foo.position.Y, foo.position.Z);

What's wrong with that? It seems perfectly straightforward.

Eric Lippert