Published on

6 Ways to Return Multiple Values From a Function in C#

Overview

There are several ways to return multiple values of different data types from a C# function. Here are some of them:

1. Output Parameters

One way to return multiple values is by using output parameters with the out keyword. The function modifies variables passed as arguments. Here's an example:

public void GetValues(out int value1, out int value2)
{
   value1 = 10;
   value2 = 20;
}

Usage:

int val1, val2;
GetValues(out val1, out val2);

This allows the function to return multiple values using out parameters.

2. Reference Parameters

The ref keyword also enables returning multiple values by passing variables by reference. Changes made inside the function reflect outside. Example:

public void MultiplyByTwoAndThree(int input, ref int output1, ref int output2)
{
    output1 = input * 2;
    output2 = input * 3;
}

Usage:

int input = 5, output1 = 0, output2 = 0;
MultiplyByTwoAndThree(input, ref output1, ref output2);
Console.WriteLine("Input: {0}, Output1: {1}, Output2: {2}", input, output1, output2);

This demonstrates returning two values using the ref keyword.

3. Using Collections or Arrays

Another approach for returning multiple values from a C# function is by using collections or arrays. Collections like lists or arrays allow you to encapsulate and return sets of values. Here's an example using an array:

public int[] GetValues()
{
    int[] values = new int[] { 10, 20 };
    return values;
}

Usage:

int[] result = GetValues();
int val1 = result[0];
int val2 = result[1];

In this example, the GetValues function returns an array of integers. The calling code then accesses individual values from the array.

Alternatively, you can use a collection type like List:

public List<int> GetValues()
{
    List<int> values = new List<int> { 10, 20 };
    return values;
}

Usage:

List<int> result = GetValues();
int val1 = result[0];
int val2 = result[1];

Using collections is beneficial when the number of values may vary, and you want the flexibility of dynamically sized containers.

4. Using Struct or Class

Structs and classes can be used to encapsulate multiple values:

Struct Example:

public struct Person
{
    public string FirstName;
    public string LastName;
    public int Age;
}

public static Person GetPerson()
{
    Person person = new Person { FirstName = "John", LastName = "Doe", Age = 30 };
    return person;
}

Usage:

Person person = GetPerson();
Console.WriteLine(person.FirstName); // John

Class Example:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

public static Person GetPerson()
{
    Person person = new Person { FirstName = "John", LastName = "Doe", Age = 30 };
    return person;
}

Usage:

Person person = GetPerson();
Console.WriteLine(person.FirstName); // John

Choose between structs and classes based on specific needs.

5. Using Anonymous Types

Anonymous types allow dynamic creation of objects. Example:

public object GetValues()
{
   int value1 = 10;
   int value2 = 20;
   return new { val1 = value1, val2 = value2 };
}

Usage:

var result = GetValues();
int val1 = result.val1;
int val2 = result.val2;

This is useful for one-time use of objects with a set of properties.

6. Using Tuple (C# version 7 and higher)

6.1. Tuple class

Introduced in C# 7.0, Tuple can be utilized to return multiple values:

public Tuple<int, int> GetValues()
{
   int value1 = 10;
   int value2 = 20;
   return Tuple.Create(value1, value2);
}

Usage:

Tuple<int, int> result = GetValues();
int val1 = result.Item1;
int val2 = result.Item2;

6.2. Named Tuple

Named tuples, introduced in C# 7, offer a concise way to define lightweight, immutable data structures:

public static (int sum, int product) Calculate(int x, int y)
{
    int sum = x + y;
    int product = x * y;
    return (sum, product);
}

Usage:

(int s, int p) result = Calculate(3, 4);
Console.WriteLine($"Sum: {result.s}, Product: {result.p}");

Named tuples enhance code readability and conciseness, especially when returning multiple values. They support deconstruction and pattern matching.