Today I learned about value types and reference types.
I am having one doubt in the code sample below:
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
FunctionSB(sb);
Console.WriteLine(sb); //sb updated
customer c = new customer();
FunctionClass(c);
Console.WriteLine(c.s);//updated class value
String str = "";
FuntionString(str);
Console.WriteLine(str);//
}
private static void FunctionSB(StringBuilder sb)
{
sb.Append("sb updated");
}
private static void FunctionClass(customer c)
{
c.s = "updated class value ";
}
static void FuntionString(String str)
{
str = "updated value";
}
}
class customer
{
public string s;
}
Here the string builder value and class member variable value is updated, but why is FuntionString(str);
not updating the str
value? (Why is it not passed as a reference?)
I's important to distinguish between a variable and an object.
Consider the code:
String str = "";
FuntionString(str);
str
is a variable. At first the value of that variable is a reference to a string. Let's say that that reference is the number 246. String 246 can be resolved to a value; it's value is an empty character array.
We then pass the value of that variable to FuntionString
. We're not passing a reference to the str
variable, we're just passing the number 246. It's a copy of that reference, or number.
Inside of that function it has an entirely different variable that happens to also be called str
. The fact that the identifier is the same doesn't change the fact that it's a different variable that just happens to have the same value.
When you change the str
variable inside of FuntionString
you do not change the str
variable from Main
. After the body of FuntionString
finishes the str
from Main
is still holding onto the reference 246, just like it was before, and the str
variable inside of FuntionString
has the value to some new reference, let's say 3, of a string new string with the value "updated value"
. That change to the variable is not reflected in Main
.
In the case of FunctionSB
the implementation of the method doesn't actually change the sb
variable. Instead of changing the variable it mutates the object that the variable is referencing. In this case sb
is pointing to the object at some location, let's say 39. The sb
in the main method and in this other method are two different variables with a copy of that same reference. The method doesn't change the sb
variable, instead it changes the sb object at location 39. The two sb
objects still both have the same value; they are unchanged, but they both "point" to a single object that has changed. As such the mutation performed with the method can be observed from Main
.
If, from the definition of FuntionString
you changed the string object that both variables pointed to, rather than changing the variable itself, then the change would be "observable" from the caller. Of course, that's not possible because strings are immutable. There is no way for the method to mutate the object in a way that the caller can observe.
The thing to realize is that, when you write str = "updated value";
, you are actually creating a new object. That is, you've done the equivalent of:
str = new string("updated value");
This means that, when you write str = "updated value"
, you're assigning a new object to the reference "str", not modifying the existing object. **
So, the correct point of comparison with regards to the "customer" class is not:
c.s = "updated class value";
But rather:
c = new customer { s = "updated class value" }.
The original object, pointed to by the reference previously held by "c" or "str", is therefore unchanged.
What you need to do in the OP case is pass the reference to the string, by using the ref
keyword:
static void FuntionString(ref String str)
{
str = "updated value";
}
The difference here is that the reference itself gets updated inside FunctionString
, and now points to the new string object.
**Note that, since .Net strings are immutable, this will always be true. It's not possible to modify a string object, only to create a new one and re-assign it. To re-state this in a slightly different way: yes, the string is passed by reference, but, since the string type is immutable, you still can't use that reference to change the object in any way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With