83

I keep getting the same issue over and over again where an object I want to reference is copied or where an object I want to copy is referenced. This happens when I use the = operator.

For example, if I am sending the object to another form, ie:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

...and then modify the object in the form, the original object does not get modified. It is as if the object was copied and not referenced. Yet, when I do this:

SomeObject myObject = new SomeObject();
SomeObject anotherObject = new SomeObject();
anotherObject = myObject;

...and then modify anotherObject, myObject gets modified as well.

The most aggravating case is when I try to Clone one of my defined objects:

public class SomeObject
{
    double value1, value2;

    //default constructor here

    public SomeObject(val1, val2)
    {
        value1 = val1;
        value2 = val2;
    }

    public void Clone(SomeObject thingToCopy)
    {
        this.value1 = thingToCopy.value1;
        this.value2 = thingToCopy.value2;
    }
}

when I do this...

SomeObject obj1 = new SomeObject(1, 2);
SomeObject obj2 = new SomeObject();
obj2.Clone(obj1);

...obj1 is referenced and any modifications to obj2 changes obj1.

System objects such as int, double, string, etc seem to always be copied, except for in the case of the clone method above.

My question is, not taking into account the use of the ref keyword in functions, when does an object get copied and when does an object get referenced in every case of the matter (i.e. when passing to functions, when setting as other objects (like the first two above examples), when copying member variables like the third example, etc.)?

BJ Myers
  • 6,617
  • 6
  • 34
  • 50
Mike Webb
  • 8,855
  • 18
  • 78
  • 111

3 Answers3

64

It's hard to answer this sort of question precisely without spending an awful lot of time picking your words carefully.

I've done so in a couple of articles which you may find useful:

That's not to say that the articles are perfect, of course - far from it - but I've tried to be as clear as I can.

I think one important thing is to separate the two concepts (parameter passing and reference vs value types) out in your head.

To look at your specific examples:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

This means that myForm.formObject and myObject refer to the same instance of SomeObject - like two people having separate pieces of paper, with each one having the same address written on them. If you go to the address on one piece of paper and paint the house red, then go to the address on the second piece of paper, you'll see a red house.

It's not clear what you mean by "and then modify the object in the form" because the type you have provided is immutable. There's no way of modifying the object itself. You can change myForm.formObject to refer to a different instance of SomeObject, but that's like scribbling out the address on one piece of paper and writing a different address on it instead. That won't change what's written on the other piece of paper.

If you could provide a short but complete program whose behaviour you don't understand (ideally a console application, just to keep things shorter and simpler) it would be easier to talk about things in concrete terms.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I will have to write one. I understand pointers for the most part from C++, I just don't understand when they are used in relation to value and reference types in C# as there is no explicit "safe" pointer usage/operators in C#. – Mike Webb Dec 03 '10 at 17:36
  • 1
    I will write the program later as now I am at work. Thank you for the help. I will read the articles as well. – Mike Webb Dec 03 '10 at 17:37
  • 3
    The analogy of address on separate pieces of paper is helpful in grasping the concept of reference types. – Martin Jul 27 '13 at 09:20
  • @Jon Skeet: Sorry to nitpick, when i tried out the example at the second link (Reference types and value types in C# / .NET) i noticed that ".Text" is left out of "Console.WriteLine ("originalPrintedPage={0}",originalPrintedPage);" – Martin Jul 27 '13 at 10:08
  • Jon, can you please explain how on low level `by value` copying is done? Does CLR use some kind of reflection and copy field by field? Or it simply copies memory area? – Johnny_D Sep 18 '14 at 20:10
  • 1
    @Johnny_D: For what kind of type? For reference types, it's *just* copying the reference - a pointer, effectively. For value types, I believe there's more subtlety involved, but it's still basically copying one chunk of memory. It doesn't need to use reflection - it knows how big the type is, and where the value is in memory. – Jon Skeet Sep 18 '14 at 20:54
  • @JonSkeet thanks for an aswer. Do you remember any article on this topic with low level details? I would like to read more. – Johnny_D Sep 19 '14 at 12:28
  • @Johnny_D: No, not offhand I'm afraid. – Jon Skeet Sep 19 '14 at 12:32
  • Not sure if the OP ever shared some code and this post is quite old I know. But I do have some code whose behaviour seem odd, not sure whether to open a new post or contribute to this one. Code is here: http://pastie.org/10785292 – Giuseppe Romagnuolo Apr 04 '16 at 16:17
  • @GiuseppeRomagnuolo: Doesn't look odd to me - `r` can't be a reference, because its type is `SearchResultEntry`. – Jon Skeet Apr 04 '16 at 17:30
  • @JonSkeet, the choice of a succint reply was in itself informative, it suggested that my eyes must have been blind to something standing right in front of them. I looked back at `SearchResultEntry` and only now realise that it is not defined as a `class` but as a `struct` and as such it is a value type. Obviously `r` can't be a reference. Thanks Jon. – Giuseppe Romagnuolo Apr 04 '16 at 20:55
11

Hi Mike All objects, which derives from ValueType, such as struct or other primitive types are value types. That means that they are copied whenever you assign them to a variable or pass them as a method parameter. Other types are reference types, that means that, when you assign a reference type to a variable, not it's value, but it's address in memory space is assigned to the variable. Also you should note that you can pass a value type as a reference using ref keyword. Here's the syntax

public void MyMethod(ref int a) { a = 25 }
int i = 20;
MyMethod(ref i); //Now i get's updated to 25.

Hope it helps :)

Davita
  • 8,928
  • 14
  • 67
  • 119
  • Sorry to nitpick here. Objects do not derive. Types do. Object is generally the term used to describe an instance of a type. – Brian Rasmussen Dec 03 '10 at 17:07
  • You can pass an argument *by* reference using `ref`, but that's not the same as passing it *as* a reference. I think it's worth differentiating between the two. – Jon Skeet Dec 03 '10 at 17:14
  • @JonSkeet: I know that this is an old question, but can you clarify or share some information about your last comment? I mean passing _by_ reference vs passing _as_ reference? thanks in advance :) I'm asking since I always thought that both will end with the same result which is affecting the passed object value if passed inside an external method. – Mohammed Swillam Sep 25 '17 at 09:18
  • @MohammedElSayed: It's probably best to just read http://jonskeet.uk/csharp/parameters.html – Jon Skeet Sep 25 '17 at 09:20
  • @JonSkeet: thanks for the quick reply, your next cup of coffee is on me ;) – Mohammed Swillam Sep 25 '17 at 09:25
1

With regards to cloning your objects if the values you are copying from one object to another are reference types then any modification to those values in the original object will affect the values in the copied object (since they are just references to the same object)

If you need to clone an object which has properties which are reference types you need to either make those types clonable or do a manual copy of them by instantiating new instances as required.

Conside using the IClonable interface though it isn't the best of solutions imho.

RobV
  • 28,022
  • 11
  • 77
  • 119