Just got this confusion running in my mind throughout the day. I am very much confused between reference and value type being passed to a method.
Say I have 2 classes
In c#, all arguments sent to method are passing by value, unless they are passed using either the ref
or out
keywords.
This includes arguments that are value types, reference types, mutable and immutable types.
When passing a reference type argument to a method, what actually happens is that the reference of the argument is passed by value.
This means that the method actually holds a new reference to the argument passed to it.
So any change to that argument's state will be also reflected when using the reference from outside the method.
However, when assigning a new value to the reference inside the method, it will not reflect on the reference outside the method.
For a better, more extensive explanation, read Jon Skeet's Parameter passing in C# article.
You can't test this using any immutable type, since immutable types, by definition, can't be changed.
You can, however, test this with any mutable type:
public static void Main()
{
var x = new List<int>();
x.Add(1);
Add(x, 2);
Console.WriteLine(x.Count.ToString()); // will print "2";
AddRef(ref x, 3);
Console.WriteLine(x.Count.ToString()); // will print "1";
Add3(x, 1, 2, 3 );
Console.WriteLine(x.Count.ToString()); // will also print "1";
Add3Ref(ref x, 1, 2, 3 );
Console.WriteLine(x.Count.ToString()); // will print "3";
}
static void Add(List<int> list, int value)
{
// adding an item to the list, thus chaning the state of the list.
// this will reflect on the list sent to the method,
// since a List is a reference type.
list.Add(value);
}
static void AddRef(ref List<int> list, int value)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// Adding the value to the list.
// Note that this change will reflect on the list passed to the method,
// since it is passed using the ref keyword.
list.Add(value);
}
static void Add3(List<int> list, int value1, int value2, int value3)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// these values are added to the new list.
// since the reference to the list was passed by value,
// it WILL NOT effect the list sent to the method.
list.Add(value1);
list.Add(value2);
list.Add(value3);
}
static void Add3Ref(ref List<int> list, int value1, int value2, int value3)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// these values are added to the new list.
// since the list was passed by reference,
// it WILL effect the list sent to the method.
list.Add(value1);
list.Add(value2);
list.Add(value3);
}
You can see for yourself on this fiddle.
Beside Reference Type
and Value Type
, there are Mutable Type
and Immutable Type
.
Immutable
means that object cannot and will not be changed after initialization. As a result, your statement only produces new string but does not modify original string.
s += "Hi";
The hello
string object remains hello
. Change is that s
is assigned with a new object helloHi
.
You are unfortunate enough using string
as an example.
Try to use mutable types like StringBuilder
in your example.
public class C
{
public static void Main(string[] args)
{
StringBuilder s = new StringBuilder("hello");
StringBuilder w = Changestring(s);
StringBuilder x = s;
}
private static StringBuilder Changestring(StringBuilder s)
{
s.Append("Hi");
return s;
}
}
First to know, passing by value doesn't change initial variable value, where passing by reference also changes initial variable value referenced by method.
By default int
treated as value type, thus it is passed by value. However, a String
even declared as a class (reference type), it is immutable by default with sealed
modifier, thus treated as passing by value and adding new characters just create new instance of String
, not changing current one.
By adding ref
keyword you can change int behavior to passing-by-reference:
public Class B
{
public static void main(string[] args)
{
int s = 99;
int w = Changeint(s); // w has changed
int x = s; // s has also changed
}
private int Changeint(ref int s)
{
s += 30; // result = 129
return s;
}
}
For class A, you need a StringBuilder instance to accomplish "helloHi":
public Class A
{
public static void main(string[] args)
{
String s = “hello”;
String w = Changestring(s);
String x = w; // if you assign s to x, you will just get "hello"
}
private string Changestring(string s)
{
StringBuilder sb = new StringBuilder();
sb.Append(s);
sb.Append(“Hi”);
return sb.ToString(); // "helloHi"
}
}
CMIIW.