Tengo una clase simple que representa coordenadas tridimensionales llamada Coord3 que simplemente tiene valores int x, y y z.
Quiero declarar una variable constante estática Coord3.zero donde x, y y z se establecen en 0.
He intentado esto con:
public static readonly Coord3 zero = new Coord3(0, 0, 0);Sin embargo, descubrí que esta variable se puede cambiar. Por ejemplo si lo hago
Coord3 coord = Coord3.zero; coord.x = 5; esto en realidad cambia el valor x de Coord3.zero a 5. ¿Tal vez estoy malinterpretando readonly ? Sé que en Unity hay Vector3.zero que nunca cambia. Estoy tratando de lograr el mismo efecto.
readonly no es exactamente lo mismo que inmutable en el sentido que quieres decir. readonly significa que no puede asignar a una variable. Entonces no podrías hacer
public static readonly Cord3 zero = new Cord3(0, 0, 0); zero = new Cord3(0, 0, 1);Para lograr el efecto que desea, es posible que deba crear una clase, una estructura o un registro con propiedades o campos de solo lectura. No hay forma de lograr ese efecto con un tipo definido en una biblioteca interna. Si el tipo permite mutabilidad en un campo o propiedad, ese campo o propiedad es mutable.
¿Quizás estoy malinterpretando
readonly?
Sí, readonly significa que no puedes cambiar la referencia de tu variable. En otras palabras, no puede escribir Coord3.zero = new(...);
Ahora, la forma en que estas cosas generalmente se escriben es como struct s, donde los campos son inmutables por defecto. Eso resolvería tu problema allí mismo. Así es también como se hace en Unity. Tenga en cuenta que también puede hacer esto con clases, al tener solo captadores en sus propiedades y completarlos una vez desde su constructor, pero las clases son muy pesadas para estos tipos pequeños.
Marcar zero como de readonly le impide cambiar lo que almacena zero . No puede reasignarlo.
zero = new Coord3(1, 1, 1); // error Tenga en cuenta que dado que Coord3 es una clase, zero.x = 5; en realidad no está cambiando lo que zero almacena. Simplemente está cambiando alguna propiedad del objeto al que se refiere el zero . zero sigue almacenando la misma referencia al mismo objeto antiguo.
Puede evitar esto al no proporcionar ninguna API pública en Coord3 que cambie los valores de sus campos, por ejemplo, al hacer que x , y , z sean todas propiedades de solo lectura:
public int X { get; } public int Y { get; } public int Z { get; } Por supuesto, esto no funcionaría si solo desea evitar establecer las propiedades en zero , pero permite la modificación de Coord3 en otros objetos.
Te sugiero que hagas de Coord3 una estructura:
public struct Coord3 { public int X { get; set; } public int Y { get; set; } public int Z { get; set; } } Ahora zero almacena los valores de los campos directamente, en lugar de una referencia a un objeto. zero.x = 5; produciría un error, porque estás modificando lo que zero almacena directamente.
Tenga en cuenta que el Vector3 de Unity, por ejemplo, también es una estructura.
Creo que puedes hacer una clase base inmutable y tu Coord3 heredando esta clase.
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); }Esto debería funcionar de manera similar a las versiones de solo lectura de las colecciones en C#. Sin embargo, creo que las soluciones de estructura son el camino a seguir.
¿Qué tal si usas una propiedad get para nunca cambiar el objeto zero ?
public class Coord3 { public static Coord3 Zero => new Coord3(0,0,0); } Entonces no podrá cambiar los valores de Zero , pero mantendrá la funcionalidad de los objetos Coord3 .
Coord3 a = Coord3.Zero; ax = 2; // changes ax, but not Coord3.Zero.x