C# Getter/Setter problem
-
21-09-2019 - |
Question
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
Solution
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;}
}
OTHER TIPS
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.
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).
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
.