5 Easy Ways to Return Multiple Values in C#
Tags: csharp, dotnet, programming, tips
Published: 2024-04-08 16:15:28

In this article, we will explore advanced strategies for creating functions that return multiple values in C#. We will dive into various techniques such as using [tuples](https://www.bytehide.com/blog/tuple-csharp), out parameters, value tuples, custom classes/structs, ref returns, pattern matching, async [methods](https://www.bytehide.com/blog/method-usage-csharp), records, dynamic objects, generics, extension methods, local functions, and discards. Each method provides a unique approach to handling multiple return values, offering flexibility and efficiency in your code.

## Using Tuples

Tuples in C# provide a way to return multiple values without the need for defining new classes or structures. Let’s explore an example showcasing the usage of tuples to calculate and return the sum and product of two numbers:

```csharp
<span class="hljs-keyword">public</span> (<span class="hljs-built_in">int</span> Sum, <span class="hljs-built_in">int</span> Product) Calculate(<span class="hljs-built_in">int</span> a, <span class="hljs-built_in">int</span> b)
{
    <span class="hljs-keyword">return</span> (a + b, a * b);
}

<span class="hljs-comment">// How to use tuples</span>
<span class="hljs-keyword">var</span> result = Calculate(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>);
Console.WriteLine(<span class="hljs-string">$"Sum: <span class="hljs-subst">{result.Sum}</span>, Product: <span class="hljs-subst">{result.Product}</span>"</span>);
```

In the code above, the `Calculate` function employs tuples to efficiently return both the sum and product of the input numbers. Tuples offer a concise and straightforward way to handle multiple return values in a single data structure.

### Real-life Example:

Consider a scenario where you need to calculate the total price and tax of a product in an e-commerce application. By utilizing tuples, you can return both values from the calculation function without the overhead of creating custom classes or structures.

### Code Explanation:

-   The `Calculate` method takes two integers `a` and `b` as input parameters.
-   It calculates the sum of `a` and `b` using `a + b` and the product using `a * b`.
-   The result is then returned as a tuple `(Sum, Product)` where `Sum` corresponds to the sum of the input numbers, and `Product` represents their product.
-   When calling the `Calculate` function with values `2` and `3`, the returned tuple is stored in the `result` variable.
-   Finally, the `[Console.WriteLine](https://www.bytehide.com/blog/console-writeline-csharp)` statement displays the sum and product values extracted from the tuple using `result.Sum` and `result.Product`.

By leveraging tuples in your C# code, you can streamline the process of returning multiple values efficiently and elegantly.

## Out Parameters

In certain cases, it becomes necessary to return additional information alongside the main return value from a method. This is where `out` parameters in C# prove to be valuable. Let’s explore a practical example involving a method that parses a date string and returns a `DateTime` object using an `out` parameter:

```csharp
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-built_in">bool</span> <span class="hljs-title">TryParseDate</span>(<span class="hljs-params"><span class="hljs-built_in">string</span> dateString, <span class="hljs-keyword">out</span> DateTime date</span>)</span>
{
    <span class="hljs-keyword">return</span> DateTime.TryParse(dateString, <span class="hljs-keyword">out</span> date);
}

<span class="hljs-comment">// How to utilize out parameters</span>
<span class="hljs-keyword">if</span> (TryParseDate(<span class="hljs-string">"2024-02-19"</span>, <span class="hljs-keyword">out</span> DateTime resultDate))
{
    Console.WriteLine(<span class="hljs-string">$"Parsed Date: <span class="hljs-subst">{resultDate.ToShortDateString()}</span>"</span>);
}
<span class="hljs-keyword">else</span>
{
    Console.WriteLine(<span class="hljs-string">"Invalid Date"</span>);
}
```

In the provided code snippet, the `TryParseDate` function is designed to attempt parsing a given date string and return the corresponding `DateTime` object via the `out` parameter.

### Real-life Example:

Imagine a situation in a finance application where user input needs to be validated, including date entries. By using an `out` parameter to return the parsed date, the application can ensure that the date format is correct and accessible for further processing.

### Code Explanation:

-   The `TryParseDate` method takes a `string` parameter representing a date in the `dateString` variable.
-   The method attempts to parse the input string as a `DateTime` object using `DateTime.TryParse`.
-   The parsed date result is returned through the `out` parameter named `date`, with the method returning a boolean indicating the success of the parsing operation.
-   In the usage example, the `TryParseDate` function is called with the date string `"2024-02-19"`, and the parsed `DateTime` value is retrieved in the `resultDate` variable.
-   If the parsing is successful, the parsed date is displayed using `resultDate.ToShortDateString()`. Otherwise, an “Invalid Date” message is shown.

The use of `out` parameters in C# facilitates returning additional information from methods and enhances the flexibility and functionality of code that requires multiple return values.

## Using ValueTuple for More Flexibility

ValueTuple in C# offers increased versatility for handling tuple operations, including deconstruction. Let’s delve into a practicable example demonstrating the utility of ValueTuple by creating a function that provides the dimensions of a geometrical shape in a `ValueTuple` structure:

```csharp
<span class="hljs-keyword">public</span> (<span class="hljs-built_in">int</span>, <span class="hljs-built_in">int</span>) GetDimensions()
{
    <span class="hljs-keyword">return</span> (<span class="hljs-number">1024</span>, <span class="hljs-number">768</span>);
}

<span class="hljs-comment">// Deconstruction of ValueTuple</span>
<span class="hljs-keyword">var</span> (width, height) = GetDimensions();
Console.WriteLine(<span class="hljs-string">$"Width: <span class="hljs-subst">{width}</span>, Height: <span class="hljs-subst">{height}</span>"</span>);
```

In the provided code segment, we define a `ValueTuple` to represent the dimensions of a shape, showcasing how to deconstruct the tuple to access individual width and height values efficiently.

### Real-life Example:

Consider an image processing application where different image sizes need to be retrieved and manipulated. By employing ValueTuple to return the width and height dimensions, developers can seamlessly extract and utilize these values for diverse image processing tasks.

### Code Explanation:

-   The `GetDimensions` method is implemented to return a `ValueTuple` representing the dimensions of a shape, specified as (1024, 768) in this instance.
-   Through deconstruction, the width and height values from the returned `ValueTuple` are extracted and assigned to the variables `width` and `height` respectively.
-   The extracted width and height values are then displayed using `Console.WriteLine`, presenting the dimensions of the shape accurately.

By leveraging ValueTuple in C# programming, one can streamline the handling of tuple operations, such as returning multiple values and deconstructing them for convenient access and manipulation. This feature contributes to code readability and enhances the flexibility of working with tuple data structures.

## Returning a Custom Class or Struct

When handling intricate sets of interconnected data, creating a custom class or struct can enhance the clarity and organization of the code. Let’s delve into an example where we define a custom class named `OperationResult` to encapsulate the outcome of a calculation:

```csharp
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">OperationResult</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> Sum { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">int</span> Product { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> OperationResult <span class="hljs-title">PerformCalculation</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> a, <span class="hljs-built_in">int</span> b</span>)</span>
{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OperationResult { Sum = a + b, Product = a * b };
}

<span class="hljs-comment">// Utilizing the Custom Class</span>
<span class="hljs-keyword">var</span> result = PerformCalculation(<span class="hljs-number">5</span>, <span class="hljs-number">4</span>);
Console.WriteLine(<span class="hljs-string">$"Sum: <span class="hljs-subst">{result.Sum}</span>, Product: <span class="hljs-subst">{result.Product}</span>"</span>);
```

In the presented code snippet, we create a custom class `OperationResult` with properties to store the sum and product values resulting from a calculation operation.

### Real-life Example:

Imagine a banking application where interest calculations need to be performed on user investments. By using a custom class like `OperationResult` to manage and return calculation outcomes, the code becomes more structured and easier to maintain.

### Code Explanation:

-   The `OperationResult` class is defined with properties `Sum` and `Product` to hold the calculated sum and product values.
-   The `PerformCalculation` method computes the sum (`a + b`) and product (`a * b`) of two input integers and returns an instance of the `OperationResult` class initialized with these values.
-   Upon invoking the `PerformCalculation` function with inputs `5` and `4`, the returned `result` object contains the calculated sum and product values.
-   The `Console.WriteLine` statement displays the sum and product values extracted from the `result` object, showcasing the encapsulation of multiple return values in a custom class.

By utilizing custom classes or structs for managing and returning complex data structures, developers can improve code readability and maintainability, particularly when dealing with multifaceted computation results.

## Using Ref Return and Ref Locals

In scenarios where direct modifications to data are required without unnecessary copying, C# provides the concept of ref returns and ref locals. Let’s explore a practical example that demonstrates how to find and return a reference to a specific name within an [array](https://www.bytehide.com/blog/array-csharp) utilizing ref returns:

```csharp
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">ref</span> <span class="hljs-built_in">string</span> <span class="hljs-title">FindName</span>(<span class="hljs-params"><span class="hljs-built_in">string</span>[] names, <span class="hljs-built_in">string</span> target</span>)</span>
{
    <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i &lt; names.Length; i++)
    {
        <span class="hljs-keyword">if</span> (names[i] == target)
        {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">ref</span> names[i]; <span class="hljs-comment">// Return a reference to the array element</span>
        }
    }

    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"Name not found"</span>);
}

<span class="hljs-comment">// How to apply ref return and ref locals</span>
<span class="hljs-built_in">string</span>[] names = { <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"Bob"</span>, <span class="hljs-string">"Charlie"</span> };
<span class="hljs-keyword">ref</span> <span class="hljs-built_in">string</span> foundName = <span class="hljs-function"><span class="hljs-keyword">ref</span> <span class="hljs-title">FindName</span>(<span class="hljs-params">names, <span class="hljs-string">"Bob"</span></span>)</span>;
foundName = <span class="hljs-string">"Bobby"</span>; <span class="hljs-comment">// Directly modifies the array</span>
Console.WriteLine(<span class="hljs-built_in">string</span>.Join(<span class="hljs-string">", "</span>, names)); <span class="hljs-comment">// Outputs: Alice, Bobby, Charlie</span>
```

In the above code segment, the `FindName` method searches for a specific name within an array and returns a reference to that element to allow direct manipulation of the array contents.

### Real-life Example:

Consider a task management application where users can update the status of tasks. Using ref returns can facilitate quick and direct updates to task properties without additional memory overhead.

### Code Explanation:

-   The `FindName` function searches for the target name within the `names` array and returns a reference to the matching element using the `ref` keyword.
-   If the target name is found, the reference to that array element is returned for direct modification.
-   In the practical implementation, the name “Bob” is located in the `names` array, and the reference to this element is assigned to `foundName` via the `FindName` method.
-   Updating `foundName` to “Bobby” directly modifies the array element, showcasing the immediate impact of ref returns on the data structure.
-   The `Console.WriteLine` statement displays the updated array elements, demonstrating the direct modification of the array contents.

By leveraging ref returns and ref locals in C#, developers can efficiently manage and update data structures, leading to enhanced performance and reduced memory consumption when working with large datasets.

## Conclusion

Implementing these methods not only enhances code readability and maintainability but also offers flexibility and efficiency in handling multiple return values. It’s essential for developers to understand the strengths and use cases of each technique to leverage them effectively in their projects.

Overall, mastering the art of returning multiple values in C# opens up a world of possibilities and empowers developers to write cleaner, more expressive code. Experimenting with these techniques and incorporating them into your coding practices will undoubtedly elevate your C# programming skills.