A lot of people seemed confused (see
this post) when passing reference types by value in the .NET Framework, as described by example 4 in this MSDN article:
C# Language Features : Passing Parameters
I can see why it is confusing but it makes sense ... when you pass a reference type by value, it passes in a copy of the reference, not a copy of the object. You now have two pointers on the stack to the same object on the heap. So while you may access the object through different references, the same object is modified.
So why isn't a copy of the object made when a reference type is passed by value? Because it's not so easy depending on the object. The example of an array of integers is kind of weak because it's easy to copy an array of integers -- in fact, it would be an understandable assumption that an array of integers is a value type, not a reference type as it happens to be -- but more on that in a moment. To answer the quesiton, for complex objects that have various constructors, etc., you can't simply copy the object. The class itself would need to implement that support, and fortunately it's standardized through the ICloneable Interface (see
this page) that lets the class implement how to copy itself.
If a situation warrants a lot of value types in a class, then use a struct instead. The struct will keep all members that are also primitives on the stack, so it will illicit the perceived correct behavior when passing by value. You can demo this with some simple code:
public struct TestStruct
{
public int a;
}
public class TestClass
{
public int a;
}
class Class1
{
[STAThread]
static void Main(string[] args)
{
TestClass tc = new TestClass();
TestStruct ts = new TestStruct();
Console.WriteLine("Testing a class:");
Console.WriteLine(tc.a);
TestClassMethod(tc);
Console.WriteLine(tc.a);
Console.WriteLine("Testing a struct:");
Console.WriteLine(ts.a);
TestStructMethod(ts);
Console.WriteLine(ts.a);
}
public static void TestClassMethod(TestClass test)
{
test.a = test.a + 3;
Console.WriteLine(test.a);
}
public static void TestStructMethod(TestStruct test)
{
test.a = test.a + 3;
Console.WriteLine(test.a);
}
|
In regards to the blog post I referenced above (pun intended), it was noted that you can then call new on the object, which repoints the reference of the object to a new instance. Of course, this makes perfect sense if you understand the reference is copied, not the object, and until new is called on that reference, it still points to the same object as the other reference.
If the receiving method needs to have a "working copy" of the object, you should use ICloneable since it encapsulates that logic into the class. It's much cleaner. If you're a new developer and still have some confusion on the topic, be sure to read MSDN's article on Types, found here:
Type Fundamentals.
