I have a general question about deep- and shallow-copy in the context of the pass-by-reference- and pass-by-value-concept of C#:
In C# it is a requirement to explicitly create methods that accept pointers/references to be able to pass such to the method. However, at least objects passed as parameters to methods/constructors are behaving differently from the rest. It seems they are always passed by reference if no extra cloning is done as described here: http://zetcode.com/lang/csharp/oopii/.
Why are objects automatically passed by reference? Is there any particular benefit from forcing the cloning process for them instead of treating objects more like int, double, boolean, etc. in these cases?
Here is code example that illustrates what I mean:
using System;
public class Entry
{
public class MyColor
{
public int r = 0;
public int g = 0;
public int b = 0;
public double a = 1;
public MyColor (int r, int g, int b, double a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
}
public class A
{
public int id;
public MyColor color;
public MyColor hiddenColor;
public A (int id, MyColor color)
{
this.id = id;
this.color = color;
}
}
static void Main(string[] args)
{
int id = 0;
MyColor col = new MyColor(1, 2, 3, 1.0);
A a1 = new A(id, col);
A a2 = new A(id, col);
a1.hiddenColor = col;
a2.hiddenColor = col;
a1.id = -999;
id = 1;
col.a = 0;
Console.WriteLine(a1.id);
Console.WriteLine(a2.id);
Console.WriteLine(a1.color.a);
Console.WriteLine(a2.color.a);
Console.WriteLine(a1.hiddenColor.a);
Console.WriteLine(a2.hiddenColor.a);
}
}
This results in:
-999
0
0
0
0
Instances of MyCol
are always passed by reference while the other arguments are passed by value. I would have to implement ICloneable in classes MyColor
and A
. On the other hand, the ´ref´-statement is present in C# which should be used to explicitly allow and do pass-by-reference.
Suggestions al welcomed!
Why are objects automatically passed by reference?
They're not.
Is there any particular benefit from forcing the cloning process for them instead of treating objects more like int, double, boolean, etc. in these cases?
There's no "cloning process" for reference types, only for value types.
I think you're confusing different concepts:
value types vs. reference types
For value types (such as primitive numeric types, enums, and structures like DateTime
), the value of the variable is the object itself. Assigning the variable to another (or passing it as a parameter by value) creates a copy of the object.
For reference types (such as object
, string
, classes (not structs) etc), the value of the variable is a reference to the object. Assigning the variable to another (or passing it as a parameter by value) creates a copy of the reference, so it still refers to the same object instance.
passing parameters by value vs. by reference
Passing parameters by value means that you pass a copy of the value. Depending on whether it's a value type or reference types, that means a copy of the object itself, or a copy of the reference. If the callee modifies members of a value type passed as a parameter, the caller won't see the changes, since the callee is working on a copy. On the other hand, if the callee modifies members of a reference type passed as a parameter, the caller will see the changes, because the callee and caller both have a reference to the same object instance.
Passing parameters by reference means that you pass a reference to a variable (which may be a variable of value type or reference type). The value is not copied: it is shared between the caller and the callee. So any change made by the callee (including assignment of a new value to the parameter) will be seen by the caller.
Unless specified otherwise (with the ref
or out
keywords), all parameters are passed by value, including reference types. It's just that for reference types, the value that is passed is a reference, but it's still passed by value.
I suggest you read Jon Skeet's article Parameter passing in C# for a better explanation.