Search code examples
c#stringextension-methodsvalue-typereference-type

Why can't I update the value of a string in an extension method?


I'm trying to create an extension method to simplify a small bit of code that I use a lot:

var test = "this is a test.";
var substring = test.Substring(0, 4);
test = test.Remove(0, 4).Trim();

After running the aforementioned code snippet and printing the resulting values for test and substring to a console window, you'll see:

this
is a test.

I'd like to simplify it with an extension method which would be an effective overload of Substring:

public static string Substring(this string input, int startingIndex, int length, bool removeFromInput = false) {
    var substring = input.Substring(startingIndex, length);
    if (removeFromInput)
        input = input.Remove(startingIndex, length);

    return substring;
}

This would allow my code going forward to be simplified to:

var test = "this is a test.";
var firstWord = test.Substring(0, 4, removeFromInput: true).Trim();
var secondWord = test.Substring(0, 2, removeFromInput: true).Trim();
var thirdWord = test.Substring(0, 1, removeFromInput: true).Trim();
var lastWord = test.Substring(0, 4, removeFromInput: true).Trim();

Let's not get pedantic and focus on the fact that I could just split on whitespace here; this isn't a universal example, and more often than not it's not focused on words but rather particular substrings.

After looking around the web for a bit, I understand why this doesn't work for value types (here is a post on that), but string is a reference type, though it's treated as a value type in many cases (here is a post on the topic). Is this another one of those cases? If so, why?


Why can't I update the value of a string in an extension method?

I'm not looking for alternatives, I'm trying to understand why this doesn't work since string is a reference type. My alternative implementation is test.Substring(0, 4, removeFrom: ref test) which I think still reads well.


Solution

  • The problem here is that although the string is a reference type, when you pass a parameter to a method that reference is copied. So a new variable is created that points to the same object in memory. When you make that variable point to a new object, it doesn't affect the original object.

    Here is an example to clarify what I mean:

    var foo = "foo";
    var bar = foo;
    
    bar = "bar";
    

    We create a string and store it's reference in the foo variable. Then we create a bar variable and store the reference of foo in it. This is a copy of the reference, now 2 variables are pointing to the same object.

    When we create a new string and assign it to bar, it doesn't affect foo. Now the bar just holds a reference to a different object.

    There is a way to make it so that the original parameter is modified and reference is not copied, and it can be done by using ref parameters. But as far as I know ref modifier is not supported for the first parameter of extension methods.