AssaultingCuccos AssaultingCuccos - 1 month ago 4
ASP.NET (C#) Question

Why is the original object changed after a copy, without using ref arguments?

At work we were encountering a problem where the original object was changed after we send a copy through a method. We did find a workaround by using

IClonable
in the original class, but as we couldn't find out why it happened in the first place.

We wrote this example code to reproduce the problem (which resembles our original code), and hope someone is able to explain why it happens.

public partial class ClassRefTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var myclass = new MyClass();
var copy = myclass;
myclass.Mystring = "jadajadajada";
Dal.DoSomeThing(copy);

lit.Text = myclass.Mystring; //Text is expected to be jadajadajada,
but ends up to be referenced
}
}

public class MyClass
{
public string Mystring { get; set; }
}

public static class Dal
{
public static int? DoSomeThing(MyClass daclass)
{
daclass.Mystring = "referenced";
return null;
}

}


As you can see, in the
DoSomething()
method we're not using any
ref
argument, but still the
lit.Text
ends up to be referenced.

Why does this happen?

Answer

It is always interesting to explain how this works. Of course my explanation could not be on par with the magnificiency of the Jon Skeet one, but I would try nevertheless.

In the old days of C programming, grasping the concept of pointers was fundamental to work with that language. So many years are passed and now we call them references but they are still ... glorified pointers and, if you understand how they work, you are half the way to become a programmer (just kidding)

So, what happen when you write

var myclass = new MyClass();

We all know that this is a call to the constructor of the class MyClass, but for the Framework it is also a request to provide a memory area where the values of the instance (property, fields and other internal housekeeping infos) live and exist in a specific point in time. Suppose that MyClass needs 100 bytes to store everything it needs. The framework search the computer memory in some way and suppose that it finds a place in memory identified by the address 4200. This value (4200) is the value that it is assigned to the var myclass It is a pointer to the memory (oops it is a reference to the object instance)

Now what happen when you call?

var copy = myclass;

Nothing particular. The copy variable gets the same value of myclass (4200). But they are referencing the same memory area so using one or the other doesn't make any difference. The memory area (the instance of MyClass) is the same located at our fictional memory address 4200.

myclass.Mystring = "jadajadajada";

This uses the reference value as a base value to find the area of memory occupied by the MyString property and sets its value to the intern area where literal strings are kept. If I could make an analogy with pointers it is like an add operation between the base memory (4200) and the offset at which is stored the reference to the string (say 42) So 4200+42 = 4242 is the point in which the reference to the literal "jadajadajada" will be stored.

Dal.DoSomeThing(copy);

Here the problem (well the point where you have the problem). When you pass the copy variable do you think that the framework repeat the search for a memory area and copy everything from the original area in a new area? No, it would be practically impossible (think about if MyClass contains a property that is an instance of another class and so on... it could never stop.) So the value passed to the DoSomeThing method is again the reference value 4200. This value is automatically assigned to the variable daclass declared as parameter of DoSomething (like you have explicitly done before with var copy = myclass;.

At this point it is clear that any operation using daClass acts on the same memory area occupied by the original instance and you see the results when code returns back to your starting point.

I beg the pardon from the more technically expert users here. Particularly for my casual and imprecise use of the term 'memory address'.

Comments