tags:

views:

138

answers:

6

In C#, I have a simple 3D vector class.

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();
}

the output is,

vector a= 10, 5, 10

vector b= 10, 5, 10

I assign a before i change a.x to 10. So i was expecting

vector a= 10, 5, 10

vector b= 0, 5, 10

From what i understand = operator assigns a reference to object like a pointer? And in C# i cant overload = operator.

Do i have to manually assign each property?

+10  A: 

Yes, because Vecor3D is a class this is quite correct.

Classes are reference types and your b = a; statement does not copy a Vector3D instance but a reference to an instance.

If you want to 'clone' the instances, you could add the IClonable interface, but that is more or less abandoned.

A better solution for an <X,Y,Z> type might be to make it a struct. Structs are values types and the meaning of b = a; would change (towards what you want).

A 3D point meets all the criteria for a struct (small, no identity). The preferred way is to design it as immutable.

Henk Holterman
Then i have to manually assign each property?
Kayhano
@Kayhano: If you want it to be a class, yes. But see the last version, best idea is to make it a struct.
Henk Holterman
If you made it a struct, it would work as you expected.
consultutah
@Kayhano, or you can change your Vector3D class to a struct (the last line of Henk's answer).
Charles Boyung
+2  A: 

Yes, reference types are assinged by reference.

If you want to have a separate instance, you want to CLONE your instance.

Create a Vector3D.Clone() method, which would look something like this:

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

Then your Main should look like this:

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();
}

But as others have said, something as small as a Vector3D would be better suited as an immutable struct

Neil N
+2  A: 

You may want to change your Vector3D class to a struct. That would let you work with a value type instead of a reference type.

Your other option is to implement ICloneable or use some other method to create a deep copy of your object.

AllenG
Arent the Vector types in XNA all `struct`?
Allen
@Allen : I haven't played with XNA at all, so I couldn't tell you. My guess would be that they are, however.
AllenG
yep, they are :) http://msdn.microsoft.com/en-us/library/bb196942(v=XNAGameStudio.40).aspx
Allen
+3  A: 

Yes, "= operator assigns a reference to object like a pointer", as you put it. Thus, both a and b reference the same single object in memory. (The object previously referenced by b is not referenced any more and will be garbage collected.)

There are multiple ways to overcome this problem:

  1. Make Vector3D a struct instead of a class. Structs are value types instead of reference types, so b = a copies the contents of a to variable b.

  2. Implement a Clone method in your Vector3D class (previously, this would mean implementing ICloneable, but this is no longer recommended). Alternatively, you could create a Vector3D constructor that takes another vector as a parameter and creates a copy.

  3. Manually copy the three values yourself (b = new Vector3D(a.x, a.y, a.z)), if you cannot change the implementation of Vector3D.

Heinzi
+1  A: 

You can make it a struct like Henk says. And you can add a 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);
    }
}   

You could also do this without adding the constructor.

b = new Vector3D() {x=0, y=0, z=0};
Tim Coker
A: 

No need to use a struct, I suggest you should design your Vector3D as an immutable class. Here are some good examples. Of course, a.x = 10 won't be possible for an immutable class.

Doc Brown