C# - TPL2141 logo C# - TPL2141

In C#, arguments can be passed to the parameters either

  1. by value, or
  2. by reference

(Docs, 2015)

Passing arguments by reference allows the changes made by the methods to be persisted at the calling site.

Pass by reference can be achieved by using the keyword ref and out, which we have covered in the topic “Functional side effects

Do note that there are slight differences among

  1. passing value-type by value
  2. passing reference-type by value
  3. passing value-type by reference
  4. passing reference-type by reference

Value-type vs. reference-type

A value-type variable directly contains the data as compared to reference-type, which contains a reference (or pointer) to the data.

Value-types include:

  1. numeric types (int, long, byte, float, double, etc)
  2. bool
  3. structs
  4. enumerations

(Docs, 2015)

Reference-types include

  1. class
  2. interface
  3. object
  4. string
  5. ..etc

(Docs, 2015)

Passing value-type by value

When a value-type is passed by value, any changes to the parameter in the method will not be persisted back in the calling environment (Docs, 2015).

Passing reference-type by value

When a reference-type is passed by value, any changes to the reference/pointer/memory location of the parameter are local; but content of the parameter can be changed (Docs, 2015).

Changing the reference of the array parameter (ie. assigning it to a new array) will not be persisted:

void ChangeReference(int[] nums)
{
    nums = new int[]{1, 2, 3, 4, 5};
}

void Main()
{
    int[] numbers = new int[] { 10, 20, 30, 40 };
    Console.WriteLine($"Original: {string.Join(", ", numbers)}");

    ChangeReference(numbers);

    Console.WriteLine($"After: {string.Join(", ", numbers)}");
}

Output:

Original: 10, 20, 30, 40
After: 10, 20, 30, 40

But changing the content of the array will be persisted:

void Main()
{
    int[] numbers = new int[] { 10, 20, 30, 40 };
    Console.WriteLine($"Original: {string.Join(", ", numbers)}");

    ChangeContent(numbers);

    Console.WriteLine($"After: {string.Join(", ", numbers)}");
}

void ChangeContent(int[] nums)
{
    nums[0] = 1;
    nums[1] = 2;
}

Output:

Original: 10, 20, 30, 40
After: 1, 2, 3, 40

Live-code example

Passing value-type by reference

When a value-type is passed by value, any changes to the parameter in the method will be persisted (Docs, 2015).

This can be achieved by using either ref or out keyword:

void Main()
{
    int result;
    Add(1, 2, out result);

    Console.WriteLine(result);
}

void Add(int first, int second, out int result)
{
    result = first + second;
}

Output:

3

Live-code example

Passing reference-type by reference

When a reference-type is passed by reference, any changes to the content and the reference/pointer/memory location of the parameter will be persisted (Docs, 2015).

In this case, changes to the reference of the array or the content of the array will both be persisted:

public static void Main()
{
    int[] numbers = new int[]{10, 20, 30, 40};
    int[] oldNumbers = numbers;	// store a temporary reference to numbers

    Console.WriteLine("--- Change reference/pointer/memory location");

    Console.WriteLine($"Original: {string.Join(", ", numbers)}");

    ChangeReference(ref numbers);

    Console.WriteLine($"After: {string.Join(", ", numbers)}");
    Console.WriteLine($"Still the same object? {numbers.Equals(oldNumbers)}");

    oldNumbers = numbers;
    Console.WriteLine();
    Console.WriteLine("--- Change content");

    Console.WriteLine($"Original: {string.Join(", ", numbers)}");

    ChangeContent(ref numbers);

    Console.WriteLine($"After: {string.Join(", ", numbers)}");
    Console.WriteLine($"Still the same object? {numbers.Equals(oldNumbers)}");
}

static void ChangeReference(ref int[] nums)
{
    nums = new int[]{1, 2, 3, 4, 5};
}

static void ChangeContent(ref int[] nums)
{
    nums[0] = 100;
    nums[1] = 200;
}

Output:

--- Change reference/pointer/memory location
Original: 10, 20, 30, 40
After: 1, 2, 3, 4, 5
Still the same object? False

--- Change content
Original: 1, 2, 3, 4, 5
After: 1, 2, 3, 4, 5
Still the same object? True

Live-code example

References

  1. Docs, M. (2015, July 20). Passing Parameters (C# Programming Guide). Retrieved from https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters
  2. Docs, M. (2015, July 20). Value Types (C# Reference). Retrieved from https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/value-types
  3. Docs, M. (2015, July 20). Reference types (C# Reference). Retrieved from https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types
  4. Docs, M. (2015, July 20). Passing Value-Type Parameters (C# Programming Guide). Retrieved from https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-value-type-parameters
  5. Docs, M. (2015, July 20). Passing Reference-Type Parameters (C# Programming Guide). Retrieved from https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters