9

For some reason, (I am new to C# and know java and c++) C# keeps copying objects when I want to pass by value. I have an arraylist of a Vector2 class, and whenever I want to increment a value, I have to do this:

Vector2 d = (Vector2) myObjects[i];
d.Y++;
myObjects [i] = d;

I want to be able to do this:

Vector2 d = (Vector2) myObjects[i];
d.Y++;

and be done. I searched the web and surprisingly no answers. BTW the vector is a struct.

Susan Yanders
  • 854
  • 1
  • 9
  • 18

2 Answers2

10

In C#, instances of classes are passed as references, whereas instances of structs are passed by copy (by default).

The answer was just where it was supposed to be: http://msdn.microsoft.com/en-us/library/vstudio/ms173109.aspx

A class is a reference type. When an object of the class is created, the variable to which the object is assigned holds only a reference to that memory. When the object reference is assigned to a new variable, the new variable refers to the original object. Changes made through one variable are reflected in the other variable because they both refer to the same data.

A struct is a value type. When a struct is created, the variable to which the struct is assigned holds the struct's actual data. When the struct is assigned to a new variable, it is copied. The new variable and the original variable therefore contain two separate copies of the same data. Changes made to one copy do not affect the other copy.

Giulio Franco
  • 3,170
  • 15
  • 18
  • 1
    If you're using Unity3D, `Vector2` is defined as a `struct`. – Giulio Franco Oct 19 '13 at 01:17
  • 1
    We had whole discussion on this yesterday. Object types are not passed by references - the reference passed by value. – T.S. Oct 19 '13 at 01:19
  • @T.S. I didn't even know structs existed in C#. However I knew that references are like pointers in c++, which are copied by value – Susan Yanders Oct 19 '13 at 01:20
  • 1
    Guys, this answer is not accurate. It explains how memory stack and heap works, not how variable passed. Totally incorrect – T.S. Oct 19 '13 at 01:30
  • 1
    Pedantic point, but classes are not 'passed' by reference -- everything is passed by value by default. The ref keyword exists for a reason! – Mark Simpson Oct 19 '13 at 01:31
  • @Mark Simpson, the ref keyword passes the reference by reference... the object is always passed by reference IIRC – NPSF3000 Oct 19 '13 at 01:40
  • 2
    @NPFS3000 -- if you pass an instance of a class to a method, a copy of the reference is made (ergo it is passed by value). It's a subtle distinction but consider this: what would happen if you do this? void SomeMethod(ClassInstance a) { a = null; } -- Whatever variable was passed in to SomeMethod will not be re-assigned to null when the method returns. – Mark Simpson Oct 19 '13 at 01:44
  • @NPSF3000 - False. You can't assign new object inside method to `objA` as follows `Method1 (objA a)` – T.S. Oct 19 '13 at 01:46
  • 1
    ... whereas it will be the case if you do SomeMethod(ref ClassInstance a). Jon Skeet has a good article on this. http://www.yoda.arachsys.com/csharp/parameters.html – Mark Simpson Oct 19 '13 at 01:46
  • @T.S. but you *can* modify the object that the referance objA refers to. The reference is (normally) passed by value, but the object is passed by reference. – NPSF3000 Oct 19 '13 at 01:47
  • 1
    Basically, it's just an unfortunate bit of terminology. Lots of people confuse 'reference types' with 'pass by reference'. – Mark Simpson Oct 19 '13 at 01:48
  • @NPSF3000, you're confusing reference types with pass by reference. I find it quite difficult to explain this due to the overloaded terms :( Check out the skeet article I linked to :) – Mark Simpson Oct 19 '13 at 01:49
  • @Mark Simpson, same as above. Your example is correct because you are modifying the reference (which is passed by value) not the object (which is passed by reference). – NPSF3000 Oct 19 '13 at 01:49
  • 1
    @NPSF3000 - you can change - yes, because you have reference to it. But the reference itself is passed by value. – T.S. Oct 19 '13 at 01:50
  • @Mark Simpson, for example, if Objects were passed by value then the following would not work: var data = new[] {1}; SomeMethod(data); print (data[0]); where SomeMethod(int[] data) {data[0] = 10;} – NPSF3000 Oct 19 '13 at 01:51
  • @T.S. as I said all along. I'm clarifying this point: "but classes are not 'passed' by reference" which is wrong - instances of classes are passed by reference (which is why we call them references). – NPSF3000 Oct 19 '13 at 01:52
  • @NPSF3000 - No. "By reference" is only when you use `ref` or `out`. It is reference of the class passed, not class by reference. – T.S. Oct 19 '13 at 01:54
  • Oh my... it was a simple question, with a simple answer. Why making it complex for subtle terminology issues?? I edited my answer, and made it less critique-prone (in my opinion). – Giulio Franco Oct 19 '13 at 01:54
  • I can't really get my point across any better in this tiny text box; all I can say is read Mr. Skeet's article. – Mark Simpson Oct 19 '13 at 01:55
  • "instances of classes are passed as references" - false - references of class is passed. By reference is when you can reassign the object, you use `ref` keyword – T.S. Oct 19 '13 at 01:56
  • 1
    @Giulio: Your answer is still incorrect, I'm afraid. Classes **are** reference types. Structs **are** value types. Both are **passed** by value unless you use the ref keyword. – Mark Simpson Oct 19 '13 at 01:57
  • Anyway, saying that instances of classes are passed by reference is not technically wrong, because the callee can affect the state of its caller (by altering the state of its local variables, if they were instances of classes, and were passed as arguments). – Giulio Franco Oct 19 '13 at 01:57
  • @Mark Simpson "Both are passed by value unless you use the ref keyword." No, the objects reference is a value type that is passed by value, the object itself is not passed by value (otherwise it'd act just like a struct which are passed by value). – NPSF3000 Oct 19 '13 at 01:59
  • @MarkSimpson I removed both the "passed by value" and the "passed by reference" expressions. I now say "passed **as** references" (which is correct, because a reference to the object is passed to the callee), and "passed **by copy**" (which is correct, because a copy of the object is made for the callee) – Giulio Franco Oct 19 '13 at 01:59
  • aaaaaaaaaaaaaaaaaaaaaaarghhhhhhhhhhhhhhhhh *dies* haha, I give up. This is going nowhere! – Mark Simpson Oct 19 '13 at 02:00
  • @Mark Simpson syou stated that: "Pedantic point, but classes are not 'passed' by reference -- everything is passed by value by default. " Which is wrong, your own linked article states: "the correct statement that object references are passed by value by default." The object *reference* is passed by value, this is NOT the object. – NPSF3000 Oct 19 '13 at 02:03
4

You are experiencing one of the effects of value-types. Because it copies itself by value, rather than by reference when assigned to new variables or passed as an argument.

You can pass a struct or other value type by ref, using the ref keyword in your method signature, unfortunately you can't use it for treating a variable in the same stack frame as a reference (i.e. you can't just say ref int test = yourArray[0], but must make something like:

public void SomeMethod(ref Vector2 input) {
   // now you are modifying the original vector2
}
public void YourOriginalMethod() 
{        
    SomeMethod(yourArray[20]);
}

In response to the comment below, from http://msdn.microsoft.com/en-us/library/14akc2c7.aspx:

Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.

Rob G
  • 3,496
  • 1
  • 20
  • 29
  • as far as I know this will involve "boxing" which is something to avoid if possible. – Dave Cousineau Oct 19 '13 at 01:36
  • 1
    In the case of C# at least when passing a struct by ref you aren't boxing it. It's just passing the reference to the location on the stack, which has a lifespan limited by its stack frame. – Rob G Oct 19 '13 at 01:41