8

I am passing a string variable to a method. I know strings are reference types but the value that I assign inside the method is lost.

public static void TestMethod(string myString)
{
    myString = "world";
}

static void Main(string[] args)
{
    string s = "hello";
    Console.WriteLine(s); // output is "hello"
    TestMethod(s);
    Console.WriteLine(s); // output is also "hello" not "world" !?
}

Anyway this does not happen with an array for example. Can someone explain why might be the cause?

user486371
  • 103
  • 1
  • 5
  • possible duplicate of [what is different between Passing by value and Passing by reference using C#](http://stackoverflow.com/questions/1293111/what-is-different-between-passing-by-value-and-passing-by-reference-using-c) – LBushkin Nov 30 '10 at 18:55
  • Can you not have TestMethod return the modified string? – vc 74 Nov 30 '10 at 18:56

4 Answers4

12

Because myString = "world" assigns a new string to the parameter, not updating the existing string. To update the original reference to the string you must pass the parameter with ref.

public static void TestMethod(ref string myString)
{
    myString = "world";
}

static void Main(string[] args)
{
    string s = "hello";
    Console.WriteLine(s); // output is "hello"
    TestMethod(ref s);
    Console.WriteLine(s); // output is also "hello" not "world" !?
}
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
3

Yes, because without a ref (or out) you can't assign a new object to a parameter. Since you didn't pass it in through a ref, the variable outside the method still references the original string which didn't change. Consequently, strings are immutable, so you can't do anything to it without create a new string once it is instantiated.

The array can be altered (or the contents of the array can be altered), because the references inside the array are not immutable (you can say reassign my_object1 to equal "BLAH"). You can replace a value in the array and have it accessible outside of the array, because the reference to the array outside of the method hasn't changed.

Link to String in MSDN (talks about immutability)

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
  • This isn't really directly related to the fact that strings are immutable. The same effect would happen with any type if you reassigned the parameter to a different instance (without it being a ref parameter. – SpeksETC Nov 30 '10 at 19:10
  • Not true, you can change the internal properties in an object that isn't immutable and have them show up outside of the method. If strings were mutable, then technically, you could change the value of it and have it appear in the calling method. Think about passing a StringBuilder object in instead of a string. You can alter it's "string value" without a ref statement. You just can't reassign an entirely new StringBuilder to that parameter. – kemiller2002 Nov 30 '10 at 19:13
  • I completely agree, just saying from the code sample in which the first line is: myString = "world" - the same thing would happen no matter what type myString was since no internal properties are being changed, the variable itself is being reassigned to a different instance. – SpeksETC Nov 30 '10 at 19:19
1

For this to work you need to add the "ref" keyword to the parameter in the method signature.

Though your string is passed by reference, when you pass it to your method you have 2 references to the same string - the one in the Main() and the one in TestMethod(). When you assign a new value to the variable in the TestMethod() you are changing its reference, but not what Main()'s variable is referencing.

If you were able to just change the string from the TestMethod() instead of reassigning then you would see the effects in the Main(), but you can't with strings since they are immutable.

To play with this further you can try the following - change TestMethod() to receive a IList and add items to this list. You can see these new items in the variable you passed in from Main(). Now if you change TestMethod(IList listArg) to first reassign listArg to a new list (i.e. listArg = new List) and then add items, the list in Main() remains unchanged. This is the same idea.

SpeksETC
  • 1,003
  • 2
  • 7
  • 13
0

Strings are immutable, which means that you can't change it's value, like you do with the items in an array. You can only replace a string object with a different string object.

The same happens if you try to replace an array object. This will put a new array in the parameter variable, but it will not change the variable that you used to call the method, and thus does not replace the array that you passed in:

public static void TestMethod(string[] myArray) {
  myArray = new string[] { "world" };
}

Parameters are always passed by value unless you use the ref or out keywords. For a reference type that means that you pass a copy of the reference.

Using the ref keyword you pass the variable, so that you can change it in the method:

public static void TestMethod(ref string myString) {
  myString = "world";
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005