I have a simple class that represents 3 dimensional coordinates called Coord3
that simply has x, y, and z int
values.
I want to declare a static constant variable Coord3.zero
where x, y, and z are set to 0.
I have attempted this with:
public static readonly Coord3 zero = new Coord3(0, 0, 0);
However I found that this variable can be changed. For example if I do
Coord3 coord = Coord3.zero;
coord.x = 5;
this actually changes the x value of Coord3.zero
to be 5. Maybe I am misunderstanding readonly
? I know that in Unity there is Vector3.zero
which never changes. I am trying to achieve the same effect.
CodePudding user response:
readonly
is not quite the same thing as immutable in the sense you mean. readonly
means you cannot assign to a variable. So you couldn't do
public static readonly Cord3 zero = new Cord3(0, 0, 0);
zero = new Cord3(0, 0, 1);
In order to achieve the effect you want, you could need to create a class, struct or record with readonly properties or fields. There's no way to achieve that effect with a type defined in an internal library. If the type allows mutability on a field or property, that field or property is mutable.
CodePudding user response:
Maybe I am misunderstanding
readonly
?
Yeah, readonly
means you can't change the reference of your variable. In other words, you can't write Coord3.zero = new(...);
Now, the way these things are usually written is as struct
s, where fields are by default immutable. That would solve your problem right there. That is also how it's done in Unity. Note that you can also do this with classes, by having only getters on your properties and filling them in once from your constructor, but classes are very heavy weight for these small types.
CodePudding user response:
Marking zero
as readonly
indeed prevents you from changing what zero
stores. You cannot reassign it.
zero = new Coord3(1, 1, 1); // error
Note that since Coord3
is a class, zero.x = 5;
isn't actually changing what zero
stores. You are just changing some property of the object that zero
is referring to. zero
is still storing the same reference to the same old object.
You could prevent this by not providing any public API in Coord3
that would change its fields' values - for example, by making x
, y
, z
all read-only properties:
public int X { get; }
public int Y { get; }
public int Z { get; }
Of course, this wouldn't work if you just want to prevent setting the properties on zero
, but allow the modification of Coord3
on other objects.
I would suggest that you make Coord3
a struct:
public struct Coord3 {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
Now zero
stores the fields' values directly, rather than a reference to an object. zero.x = 5;
would produce an error, because you are modifying what zero
directly stores.
Note that Unity's Vector3
for example, is also a struct.
CodePudding user response:
I am trying to achieve the same effect.
For This effect, You can use it this way.
void Main()
{
Coord3 zero = new Coord3();
zero.Zero();
}
public class Coord3
{
public Coord3()
{
}
public Coord3(int x,int y,int z)
{
X=x;
Y=y;
Z=z;
}
public void Zero(){
X=0;
Y=0;
Z=0;
}
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
CodePudding user response:
I think you can make an immutable base class and your Coord3
inheriting this class.
public class BaseCoord3
{
// protected means it can only be used by BaseCoord3 and Coord3
protected int x;
// equivalent to public int X { get { return x; } }
public int X => x;
}
public class Coord3 : BaseCoord3
{
public override int X
{
get { return x; }
set { x = value; }
}
public static BaseCoord3 Zero => new BaseCoord3(0,0,0);
}
This should work similar to the way with Readonly versions of collections in c#. I think the struct solutions are the way to go though.
CodePudding user response:
How about you just use a get-property to never change the zero
object?
public class Coord3
{
public static Coord3 Zero => new Coord3(0,0,0);
}
Then you won't be able to change the values of Zero
, but you will maintain the functionality of Coord3
objects.
Coord3 a = Coord3.Zero;
a.x = 2; // changes a.x, but not Coord3.Zero.x