Return multiple values from a function in C#
There are several ways in C# to implement a method that returns multiple values. Here are a few of them, with as much information as possible about each one.
-
1
Using a class
This approach, probably the most common one, is to use a class as the return value. You are then completely free to return whatever you want, since you fully define the object that will be returned.public sealed class MyReturnContainer { public Guid GuidValue { get; } public string StringValue { get; } public int IntValue { get; } public MyReturnContainer(Guid g, string s, int i){ GuidValue = g; StringValue = s; IntValue = i; } }public class AnotherClassSomewhereInYourCode { public AnotherClassSomewhereInYourCode() { } public MyReturnContainer GetMultipleValues(){ return new MyReturnContainer(Guid.NewGuid(), "string value", 1); } }Benefits of returning a class:
- Total flexibility
- Supports asynchrony
Cons of returning a class:
- Classes are reference types (less efficient than value types)
- If the class has no real business meaning, or is used only once, it can needlessly bloat your model
-
2
Using output parameters (out)
Output parameters allow you to declare that a method has one or several output values in addition to its return value.
An out parameter tells the compiler that the object will only be initialized inside the function, so an out parameter can only be an output value because its value cannot be initialized beforehand. Moreover, a method that has out parameters must assign a value to all of them. A method with unassigned out parameters will cause a compilation error.
Guid myGuid = Guid.Empty; string myString = string.Empty; int myInt = 0; public bool GetMultipleValues(out Guid g, out string s, out int i){ g = Guid.NewGuid(); s = "string value"; i = 1; return true; } bool ret = GetMultipleValues(out myGuid, out myString, out myInt); Console.WriteLine(myString); // "string value"Note that an out parameter can be nullable.
public bool TryCreateSomething(string param1, string param2, bool param3, out Guid? id){ id = null; // do something return true; }Finally, with C# 7.0, output parameters no longer have to be declared before being passed as parameters, they can be declared on the fly, like this:
public void PrintCoordinates(Point p) { p.GetCoordinates(out int x, out int y); Console.WriteLine($"({x}, {y})"); }Benefits of using output parameters:
- Flexibility
Cons of using output parameters:
- Doesn't support asynchrony
- You are required to assign a value, even a null one
-
3
Using parameters passed by reference (ref)
Passing one or several parameters by reference means that any change of value made inside a method will be reflected on the original variable, outside the method.
Unlike output parameters (out), any parameter passed by reference to a method must be initialized beforehand, but it doesn't necessarily have to be assigned a value by that same method.
Since a ref parameter has a value even before the method runs, it is called a two-way parameter, because its value can be used inside a method even if that method hasn't assigned anything to it yet.
string message = "Hello"; public void AlterMyMessage(ref string message){ message = "Hi there !"; } Console.WriteLine(message); // "Hello" AlterMyMessage(ref message); Console.WriteLine(message); // "Hi there !"Benefits of passing by reference:
- Flexibility
- Two-way
Cons of passing by reference:
- Doesn't support asynchrony
-
4
Tuples
Introduced with the .NET Framework 4.0, Tuple objects let you create custom and complex objects without having to declare a class. They can contain as many parameters as you want (the .NET framework supports up to 7 elements, but you can get around this limitation by nesting Tuple objects in the Rest property of a Tuple), of any type. When you use them, these parameters are named ItemX, X being their position (Item1 for the first parameter, Item2 for the second one, and so on).
class TupleExample { static void Main() { // Instantiating a Tuple with 3 parameters Tuple<int, string, bool> tuple = new Tuple<int, string, bool>(10, "string value", true); // Accessing the properties of the created Tuple if (tuple.Item1 == 10) { Console.WriteLine(tuple.Item1); } if (tuple.Item2 == "string") { Console.WriteLine(tuple.Item2); } if (tuple.Item3) { Console.WriteLine(tuple.Item3); } } }Technically, a Tuple is a class that provides static methods to create instances.
Although this object turns out to be extremely handy and useful in a lot of cases, it should still be used sparingly, as it is not always easy to maintain over time. Indeed, when you come back to a method 2 years after writing it, it is sometimes hard to remember what the Item4, Item5 and Item6 properties stand for... That said, it seems that this will not be a limitation for much longer, as this GitHub issue shows. What's more, if you decide to add a parameter in second position, then the names of all the following parameters will be impacted.
Benefits of returning a Tuple:
- Avoids needlessly bloating the model
- Total flexibility
- Supports asynchrony
Cons of returning a Tuple:
- Abstract naming of the properties
- Maintainability
- Performance (reference type)
-
5
Using a dictionary entry (KeyValuePair)
class KeyValuePairExample { static void Main() { KeyValuePair<int, string> kvp = GetKeyValuePair(); } KeyValuePair<int, string> GetKeyValuePair(){ return new KeyValuePair<int, string>(1, "string value"); } }Benefits of returning a KeyValuePair:
- Ease of use (the class already implements some querying methods, among others)
- Supports asynchrony
- Uniqueness of the key/value pairs (in the case of a dictionary)
Cons of returning a KeyValuePair:
- Performance (less efficient than a 2-parameter Tuple, or than a structure)
-
6
Using a structure (struct)
Structures are an alternative to classes, and they are value types, unlike classes which are reference types. Although structures have far more limitations than classes, they are far more efficient, which is why it is better to use structures when you can, especially if the data structure in question will be instantiated a lot.
Main limitations of structures compared to classes:
- Inheritance is not possible
- All the properties must have a value
- Parameterless constructors are not possible (they had been added in C# 6 but have been removed since, and are apparently not being considered for C# 7)
- Every constructor must assign a value to each property of the structure (otherwise the default value of the type will be assigned)
public struct Point { public int x, y; // Constructor: public Point(int x, int y) { this.x = x; this.y = y; } // Override the ToString method: public override string ToString() { return(String.Format("({0},{1})", x, y)); } }Benefits of returning a structure:
- Value type (performance++)
- Simplicity
- Supports asynchrony
Cons of returning a structure:
- Rigidity of the object

