The Tuple class in C# is a handy little structure for grouping together a sequence of elements, and it comes in various flavors depending on how many items you need to hold. Think of it like a lightweight container. The following is an example of Tuple class with two elements:
public class Tuple<T1, T2> : IStructuralComparable, IStructuralEquatable, IComparable, ITuple
{
public Tuple(T1 item1, T2 item2);
public T1 Item1 { get; }
public T2 Item2 { get; }
public override bool Equals([NotNullWhen(true)] object? obj);
public override int GetHashCode();
public override string ToString();
}
Look at Tuple More Closely
In Visual Studio, you see that Tuple is a non-generic static class defined in System namespace. Here, Tuple has 8 Create methods. Each Create method is generic in nature. Tuple class contains only Create methods. These Create methods are used to create tuple objects with one or more items.
Therefore, Static Non-Generic Tuple class is a wrapper class for Non-static Generic Tuple classes. To create an instance of Generic Tuple, Static Non-Generic Tuple class Create method is used.
Look at the Tuple class definition:
Go to definition of ITuple interface. It contains an indexer and Length property. It is implemented by all Generic Tuple classes.
Example of Tuple Variable
Tuple vs. ValueTuple
| Feature | Tuple | ValueTuple |
| Introduced | C# 4.0 / .NET 4.0 | C# 7.0 |
| Type | Reference type (class) | Value type (struct) |
| Namespace | System.Tuple | System.ValueTuple |
| Naming | Item1, Item2 | Named fields supported |
| Performance | Heap allocation | Usually stack/value semantics |
| Mutability | Immutable | Mutable |
Tuple declaration and initialization
In C#, you can declare and initialize a tuple in a few different ways, depending on the version of C# and .NET you’re using.
Using the Tuple Class (Before C# 7.0) For versions before C# 7.0, tuples can be created using the Tuple class.// Declare and initialize a tuple with two items
var tuple = Tuple.Create(1, "Hello");
// Access tuple items
int item1 = tuple.Item1; // 1
string item2 = tuple.Item2; // "Hello"
Note: The Tuple class supports up to 8 items (Tuple<T1, T2, ..., T8>), and the elements are accessed using Item1, Item2, etc. It doesn’t have named fields, making it less readable. You can store more than 8 items but for this generally the 8th item is another tuple. Here is an example in which 6th element is another tuple with 5 elements:
var tuple = new Tuple<int, int, int, int, int, Tuple<int, int, int, int, int>, int>(
1, 2, 3, 4, 5,
new Tuple<int, int, int, int, int>(6, 7, 8, 9, 10),
11
);
Console.WriteLine($"Item1: {tuple.Item1}"); // Output: Item1: 1
Console.WriteLine($"Item2: {tuple.Item2}"); // Output: Item2: 2
Console.WriteLine($"Item3: {tuple.Item3}"); // Output: Item3: 3
Console.WriteLine($"Item4: {tuple.Item4}"); // Output: Item4: 4
Console.WriteLine($"Item5: {tuple.Item5}"); // Output: Item5: 5
Console.WriteLine($"Item6: {tuple.Item6}"); // Output: Item6: (6, 7, 8, 9, 10) - This is the inner tuple
Console.WriteLine($" Item6.Item1: {tuple.Item6.Item1}"); // Output: Item6.Item1: 6
Console.WriteLine($" Item6.Item5: {tuple.Item6.Item5}"); // Output: Item6.Item5: 10
Console.WriteLine($"Item7: {tuple.Item7}"); // Output: Item7: 11
Rest property: Tuple has Rest property which is used to access items of 8th element of a tuple, if 8th element is another tuple. Here aTuple.Rest refers to the 8th element of aTuple. aTuple.Rest will throw error if 8th element is not a tuple.var aTuple = new Tuple<int, int, int, int, int, int, int, Tuple<int>>(1, 2, 3, 4, 5, 6, 7, new Tuple<int>(8));
Console.WriteLine($"Element 1: {aTuple.Item1}");
Console.WriteLine($"Element 7: {aTuple.Item7}");
Console.WriteLine($"Element 8: {aTuple.Rest.Item1}");
Invalid use of Rest property: The following example shows invalid use of Rest property:
var bTuple = new Tuple<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Element 1: {bTuple.Item1}");
Console.WriteLine($"Element 7: {bTuple.Item7}");
Console.WriteLine($"Element 8: {bTuple.Rest.Item1}"); // ERROR
// Declare and initialize a value tuple with two items
var tuple = (1, "Hello");
// Access tuple items
int item1 = tuple.Item1; // 1
string item2 = tuple.Item2; // "Hello"
Named ValueTuples (C# 7.0 and Later)
With value tuples, you can assign names to tuple elements for improved readability.// Declare and initialize a named value tuple
var tuple = (id: 1, message: "Hello");
// Access tuple items by name
int id = tuple.id; // 1
string message = tuple.message; // "Hello"
Explicit Tuple Types
You can also declare an explicit type for a tuple variable, which is useful for method parameters and return values.// Explicitly declare a tuple type
(string name, int age) person = ("Alice", 30);
// Access tuple items
string name = person.name; // "Alice"
int age = person.age; // 30
Summary
- Class Tuple: var tuple = Tuple.Create(1, "Hello");
- Value Tuple: var tuple = (1, "Hello");
- Named Value Tuple: var tuple = (id: 1, message: "Hello");
- Explicitly Typed Value Tuple: (string name, int age) person = ("Alice", 30);
Example of how to create and use a tuple in C#:
using System;
class Program
{
static void Main(string[] args)
{
// Creating a tuple with named elements
(string name, int age) person = ("John Doe", 30);
// Accessing tuple elements using names
Console.WriteLine("Name: " + person.name);
Console.WriteLine("Age: " + person.age);
// Creating a tuple without named elements
var coordinates = (x: 10, y: 20);
// Accessing tuple elements using default names (Item1, Item2, etc.)
Console.WriteLine("X coordinate: " + coordinates.Item1);
Console.WriteLine("Y coordinate: " + coordinates.Item2);
// Deconstructing a tuple into individual variables
var (xCoord, yCoord) = coordinates;
Console.WriteLine("Deconstructed X coordinate: " + xCoord);
Console.WriteLine("Deconstructed Y coordinate: " + yCoord);
}
}
System.ValueTuple Initialization Examples
Before the assignment operator, we can use datatype and variable name for each item of tuple in round brackets in following styles:- (datatype1 var1, datatype2 var2, datatype3 var3 …)= (value1, value2, value3, …)
- (datatype1, datatype2, datatype3 …) variable1 = (value1, value2, value3, …)
- var (var1, var2, var3 …)= (value1, value2, value3, …)
- var tuplevar = (value1, value2, value3, …)
- var tuplevar = (name1: value1, name2: value2, name3: value3, …)
var mytuple = (1, 4, "Test");
Console.WriteLine(mytuple.Item1);
Console.WriteLine(mytuple.Item2);
Console.WriteLine(mytuple.Item3);
We can use separate variable for each item of tuple (DE structuring):var (first, second, third) = (1, 4, "Test");
Console.WriteLine(first);
Console.WriteLine(second);
Console.WriteLine(third);
We can use separate name for each item of tuple:var mytuple = (first: 1, second: 4, third: "Test");
Console.WriteLine(mytuple.first);
Console.WriteLine(mytuple.second);
Console.WriteLine(mytuple.third);
You can force datatype of each tuple item during declaration:(int, int, string) mytuple = (1, 4, "Test");
Console.WriteLine(mytuple.Item1);
Console.WriteLine(mytuple.Item2);
Console.WriteLine(mytuple.Item3);
You can force datatype and variable name of each tuple item during declaration:
(int first, int second, string third) = (1, 4, "Test");
Console.WriteLine(first);
Console.WriteLine(second);
Console.WriteLine(third);
Applications of Tuple
public (string, int) GetPersonInfo()
{
return ("John Doe", 30);
}
public (string Name, int Age) GetPersonInfo()
{
return ("John Doe", 30);
}
(string name, int age) = GetPersonInfo();
public void DisplayPersonInfo((string Name, int Age) person)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
List<(string, int)> personList = new List<(string, int)>
{
("Alice", 25),
("Bob", 30)
};
var result = from person in persons
where person.Age > 30
select (person.Name, person.Age);
public (int sum, int product) CalculateSumAndProduct(int a, int b)
{
int sum = a + b;
int product = a * b;
return (sum, product);
}
Features of ValueTuple
var myTuple = (value1, value2, value3);
var namedTuple = (first: "John", last: "Doe");
Console.WriteLine($"{namedTuple.first} {namedTuple.last}");
var (firstName, lastName) = namedTuple;
public (int sum, int count) CalculateSumAndCount(int[] numbers)
{
int sum = 0;
foreach (var num in numbers)
sum += num;
return (sum, numbers.Length);
} var inferredTuple = (42, "hello");
Is Tuple Generic?
Declaration
// Tuple with two elements of generic types
Tuple<int, string> tuple = new Tuple<int, string>(1, "Hello");
// Tuple with three elements of generic types
Tuple<int, string, bool> tuple = new Tuple<int, string, bool>(1, "Hello", true);var tuple = new Tuple<int, string, double>(1, "Hello", 3.14);
// Access the items
Console.WriteLine(tuple.Item1); // 1
Console.WriteLine(tuple.Item2); // Hello
Console.WriteLine(tuple.Item3); // 3.14
(int, string, bool) valueTuple = (1, "Hello", true);
Console.WriteLine(valueTuple.Item1); // 1
Console.WriteLine(valueTuple.Item2); // Hello
Console.WriteLine(valueTuple.Item3); // True
There are 2 approaches to create a reference type tuple:
- Static method, Tuple.Create()
- Constructor
Example. Create reference type tuples
var t0 = Tuple.Create(); // cannot create tuple with no elements
var t1 = Tuple.Create("Ajeet"); // creates tuple with one element
var t2 = Tuple.Create(1, "Hello"); // creates tuple with two elements
Tuple<int, string> t3 = new Tuple<int, string>(1, "Ajeet"); // using constructor
Similarly, There are 2 approaches to create a value type tuple:
- Static method, ValueTuple.Create()
- Constructor
Example. Create value type tuples
var vt = ValueTuple.Create(); // creates value tuple with no elements
var vt1 = ValueTuple.Create("Ajeet"); // creates value tuple with one element
var vt2 = ValueTuple.Create(1, "Hello"); // creates value tuple with two elements
ValueTuple<int, string> vt3 = new ValueTuple<int, string>(1, "Ajeet"); // using constructorExample. Equality Test using == operator for Value type and Reference type tuples. The following example shows that value tuple is good condidate for values based equality test of two objects.
Tuple<int, string> tuple1 = new Tuple<int, string>(1, "Ajeet");
Tuple<int, string> tuple2 = new Tuple<int, string>(1, "Ajeet");
ValueTuple<int, string> valueTuple1 = new ValueTuple<int, string>(1, "Ajeet");
ValueTuple<int, string> valueTuple2 = new ValueTuple<int, string>(1, "Ajeet");
Console.WriteLine(tuple1 == tuple2);
Console.WriteLine(valueTuple1 == valueTuple2);
Console.WriteLine(tuple1.GetType());
Console.WriteLine(valueTuple1.GetType());
/*
False
True
System.Tuple`2[System.Int32,System.String]
System.ValueTuple`2[System.Int32,System.String]
*/



No comments:
Post a Comment