So strings are reference types right? My understanding is a reference to the string in the heap is passed even when you pass the string ByVal to a method.
Sooo.....
String myTestValue = "NotModified";
TestMethod(myTestValue);
System.Diagnostics.Debug.Write(myTestValue); /* myTestValue = "NotModified" WTF? */
private void TestMethod(String Value)
{
Value = "test1";
}
Alternatively
Dim myTestValue As String = "NotModified"
TestMethod(myTestValue)
Debug.Print(myTestValue) /* myTestValue = "NotModified" WTF? */
Private Sub TestMethod(ByVal Value As String)
Value = "test1"
End Sub
What am I missing? And what is going on under the hood? I would have bet my life that the value would have changed....
Reference types are passed "reference by value" in .NET. This means that assigning a different value to the actual parameter does not actually change original value (unless you use ByRef/ref). However, anything you do to change the actual object that gets passed in will change the object that the calling method refers to. For example, consider the following program:
void Main()
{
var a = new A{I=1};
Console.WriteLine(a.I);
DoSomething(a);
Console.WriteLine(a.I);
DoSomethingElse(a);
Console.WriteLine(a.I);
}
public void DoSomething(A a)
{
a = new A{I=2};
}
public void DoSomethingElse(A a)
{
a.I = 2;
}
public class A
{
public int I;
}
Output:
1
1
2
The DoSomething
method assigned its a
parameter to have a different value, but that parameter is just a local pointer to the location of the original a
from the calling method. Changing the pointer's value did nothing to change the calling method's a
value. However, DoSomethingElse
actually made a change to one of the values on the referenced object.
Regardless of what the other answerers say, string
is not exceptional in this way. All objects behave this way.
Where string
differs from many objects is that it is immutable: there aren't any methods or properties or fields on string that you can call to actually change the string. Once a string is created in .NET, it is read-only.
When you do something like this:
var s = "hello";
s += " world";
... the compiler turns this into something like this:
// this is compiled into the assembly, and doesn't need to be set at runtime.
const string S1 = "hello";
const string S2 = " world"; // likewise
string s = S1;
s = new StringBuilder().Append(s).Append(S2).ToString();
This last line generates a new string, but S1 and S2 are still hanging around. If they are constant strings built into the assembly, they'll stay there. If they were created dynamically and have no more references to them, the garbage collector can de-reference them to free up memory. But the key is to realize that S1 never actually changed. The variable pointing to it just changed to point to a different string.