0

I'm playing around with C# extensions and am confused about mutate methods.

Below are two code samples that are supposed to change the calling List. The first (shuffle) works but the second (CustomExtension) leaves the List unchanged.

At the end of the CustomExtension call the list parameter looks to be changed, but on returning from the method the List looks untouched.

Why does one work and the other doesn't? What's going on?

This works.

readonly private static Random rng = new Random();
public static void Shuffle<T>(this IList<T> list)
{

    int n = list.Count;
    while (n < 1)
    {
        n--;
        int k = rng.Next(n + 1);
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
    }
}
myList.Shuffle();

(The above was ripped from Randomize a List<T>)

This Doesn't

static void CustomExtension(this IList<int> list)
{
    list = new List<int>() { 9, 10, 11 };
}
foo.CustomExtension();
Brad
  • 13
  • 5
  • Just so happens Microsoft has preempted this sort of question and documented it thoroughly (since the beginning of C# time) https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters – TheGeneral Jun 18 '20 at 01:00
  • @TheGeneral That article doesn't mention extension-methods or the fact you can't have a `ref this` parameter though. – Dai Jun 18 '20 at 01:25
  • @Dai, yeah you are correct, on a side note, didn't they allow the first parameter of extension methods to use ref since C# 7.2 ? – TheGeneral Jun 18 '20 at 01:30
  • For future weary traveller, here is the documentation for extension methods. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods#common-usage-patterns – TheGeneral Jun 18 '20 at 01:33

1 Answers1

1

In the first example, you're overwriting elements inside the List<T>. This mutates the list in-place.

In the second example you're creating a new list and replacing the local reference list which is a parameter which is not being passed using ref, so it has no effect outside of the scope of the method. Your foo instance is not being mutated in CustomExtension.

Extension methods in C# cannot pass the this parameter using ref so you cannot overwrite the caller's instance reference.

If you change the method and call-site to a normal method with a ref parameter, then it works as expected (but it still isn't mutating foo, it's replacing it):

static void CustomExtension(ref IList<int> list)
{
    list = new List<int>() { 9, 10, 11 };
}

CustomExtension( ref foo );
Dai
  • 141,631
  • 28
  • 261
  • 374