C# has two different types of variables: value types and reference types. While in C and C++ primitive types can contain values or references and certain complex types (arrays, objects) can only be used via reference, in C# the line between the two types is very clear. Numeric types(int, decimal, double, etc.), bool and structs access the values directly. Class, object, interface, delegate string and dynamic are only accessed and used via reference. Because of all the awkwardness with referencing and dereferencing in C and C++, C# uses the ‘ref’ keyword only for those cases where you want to modify a value type outside of your current scope.
If you’ve worked with C# a bit you’re probably used to always working with copies in any situation outside of simple assignment (=). If you loop over a collection, inside the loop you’re working with copies. If you pass something to a function, that something is a copy. However the difference between value types and reference types often means a copy isn’t always a copy. Knowing when this is not the case can help you spot troublesome bugs, and easily solve problems that might have taken you much longer. Here are a few example cases:
Example class:
class MyClass { public int Value; public MyClass(int value) { this.Value = value; } public static void Increment1(int i) { i++; } public static void Increment2(ref int i) { i++; } public static void Increment3(MyClass o) { o.Value++; } }
int i = 9; int j = i; //j stores a copy of the value of i var myObject = new MyClass(9); var myObject2 = myobject; // myObject2 stores a copy of the reference to myObject so // any modifications to myObject2 will be reflected in // myObject as well
List myList = new List{1, 2, 3}; List myObjectList = new List { new MyClass(1), new MyClass(2), new MyClass(3) }; foreach(var i in myList) i++; //doesn't change anything in the original list since i is a copy foreach(var o in myObjectList) o.Value++; // o is a copy of the reference to each o object, so any operations on // its interior values change the original object foreach(var o in myObjectList) o = new MyClass(o.Value++); // doesn't change anything since you're assigning a // new reference to a variable that contains a copy // of the reference to the original object
int i = 9; var o = new MyClass(9); MyClass.Increment1(i); // does nothing since it's working on a copy of i MyClass.Increment2(ref i); // works since i is passed by reference MyClass.Increment3(o); // works since a copy of the reference to o is passed so any // work on o'smembers changes the location in memory o refers // to, not o itself
Quick Links
Legal Stuff