2010-07-27 11 views
6

En C#, tengo una clase vectorial 3D simple.C# = problema del operador

static void Main(string[] args) 
{ 
    Vector3D a, b; 
    a = new Vector3D(0, 5, 10); 
    b = new Vector3D(0, 0, 0); 

    b = a; 
    a.x = 10; 

    Console.WriteLine("vector a=" + a.ToString()); 
    Console.WriteLine("vector b=" + b.ToString()); 
    Console.ReadKey(); 
} 

la salida es,

vector a = 10, 5, 10

vector b = 10, 5, 10

asigno un hacha antes de que cambie a 10. Así i esperaba

vector a = 10, 5, 10

vector b = 0, 5, 10

Por lo que entiendo = ¿el operador asigna una referencia al objeto como un puntero? Y en C# no puedo sobrecargar = operador.

¿Debo asignar manualmente cada propiedad?

+5

La mejor práctica aquí sería hacer que un tipo * inmutable *, ya sea un tipo de referencia o un tipo de valor, no importe. Los vectores son lógicamente * valores *. Cuando sumas de cuatro a doce, lógicamente no "muta" los dos en seis y mantienes uno igual. Haces un número completamente nuevo por completo. De manera similar, cuando cambias la coordenada x de un vector, no cambias la coordenada x y mantienes igual a y y z: creas un vector completamente nuevo. Descubrirá que es mucho más capaz de razonar sobre matemáticas vectoriales si trata los valores como valores, no como estado mutable. –

Respuesta

10

Sí, porque Vecor3D es una clase esto es bastante correcto.

Las clases son tipos de referencia y su instrucción b = a; no copia una instancia de Vector3D sino una referencia a una instancia.

Si desea 'clonar' las instancias, puede agregar la interfaz IClonable, pero eso es más o menos abandonado.

Una mejor solución para un tipo <X,Y,Z> podría ser convertirla en una estructura. Las estructuras son tipos de valores y el significado de b = a; cambiaría (hacia lo que desee).

Un punto 3D cumple todos los criterios para una estructura (pequeña, sin identidad). La forma preferida es diseñarlo como inmutable.

+0

¿Entonces tengo que asignar manualmente cada propiedad? – Kayhano

+0

@Kayhano: si quieres que sea una clase, sí. Pero mira la última versión, la mejor idea es hacer que sea una estructura. –

+0

Si lo hizo una estructura, funcionaría como esperaba. – ConsultUtah

2

Sí, los tipos de referencia se asignan por referencia.

Si quiere tener una instancia separada, quiere CLONE su instancia.

Crear un método Vector3D.Clone(), que sería algo como esto:

public Vector3D Clone() 
{ 
    return new Vector3D(this.x, this.y, this.x); 
} 

Luego, su principal debería tener este aspecto:

static void Main(string[] args) 
{ 
    Vector3D a, b; 
    a = new Vector3D(0, 5, 10); 
    b = new Vector3D(0, 0, 0); 

    b = a.Clone(); 
    a.x = 10; 

    Console.WriteLine("vector a=" + a.ToString()); 
    Console.WriteLine("vector b=" + b.ToString()); 
    Console.ReadKey(); 
} 

Pero, como otros han dicho, algo tan pequeño como un Vector3D sería más adecuado como una estructura inmutable

2

Es posible que desee cambiar su clase Vector3D a una estructura. Eso le permitiría trabajar con un tipo de valor en lugar de un tipo de referencia.

Su otra opción es implementar ICloneable o utilizar algún otro método para crear una copia profunda de su objeto.

+0

Arent the Vector types in XNA all 'struct'? –

+0

@ Allen: No he jugado con XNA en absoluto, así que no podría decírtelo. Sin embargo, creo que sí lo son. – AllenG

+0

sí, son :) http://msdn.microsoft.com/en-us/library/bb196942(v=XNAGameStudio.40).aspx –

3

Sí, "= el operador asigna una referencia al objeto como un puntero", como usted lo dice. Por lo tanto, tanto a como b hacen referencia al mismo objeto simple en la memoria.(El objeto anteriormente referenciado por b no se hace referencia más y será recogido de basura.)

Existen múltiples maneras de superar este problema:

  1. gane Vector3D un struct en lugar de una clase. Las estructuras son valor tipos en lugar de tipos de referencia, por lo que b = acopia el contenido de a a la variable b.

  2. implementar un método Clone en su clase Vector3D (anteriormente, esto significaría la implementación ICloneable, pero this is no longer recommended). Alternativamente, puede crear un constructor Vector3D que tome otro vector como parámetro y cree una copia.

  3. Copie manualmente los tres valores (b = new Vector3D(a.x, a.y, a.z)), si no puede cambiar la implementación de Vector3D.

1

Puede hacer que sea una estructura como dice Henk. Y puede agregar un constructor

struct Vector3D 
{ 
    public int x; 
    public int y; 
    public int z; 

    public Vector3D(int x, int y, int z) 
    { 
     this.x = x; 
     this.y = y; 
     this.z = z; 
    } 
    public override string ToString() 
    { 
     return string.Format("{0}, {1}, {2}", x, y, z); 
    } 
} 

También podría hacer esto sin agregar el constructor.

b = new Vector3D() {x=0, y=0, z=0}; 
0

No hay necesidad de utilizar un struct, le sugiero que debe diseñar su Vector3D como inmutable clase. Here son algunos buenos ejemplos. Por supuesto, a.x = 10 no será posible para una clase inmutable.