.NET HELP

C# Pair Class (How It Works For Developers)

Published June 6, 2024
Share:

Introduction

A pair is a simple data structure that holds two related values. It provides a convenient way to bundle two distinct pieces of data together. Pairs are commonly used when a method needs to return two values or when working with key-value associations.

In C#, developers often resort to using tuples (Tuple<T1, T2>) for pairing values. However, tuples are immutable, and their elements are accessed via properties like Item1 and Item2, which can lead to less readable code when used extensively. This is where a custom Pair class comes in handy.

If you require a structure to hold two related objects and data hiding is not a priority, you can utilize the Pair class in your code. The Pair class does not encapsulate its object references. Instead, it exposes them directly to all calling codes as public class fields.

This design choice allows for straightforward access to the contained objects without the overhead of encapsulation. Also, at the end of the article, we will explore how IronPDF from Iron Software can be used to generate a PDF document.

Tuples

C# 7.0 introduced tuple syntax improvements, making tuples even easier to work with. Here's how you can declare and initialize tuples:

// Tuple declaration
var person = (name: "John", age: 30);
// Accessing tuple elements
Console.WriteLine($"Name: {person.name}, Age: {person.age}");
// Tuple deconstruction
var (name, age) = person;
Console.WriteLine($"Name: {name}, Age: {age}");
// Tuple declaration
var person = (name: "John", age: 30);
// Accessing tuple elements
Console.WriteLine($"Name: {person.name}, Age: {person.age}");
// Tuple deconstruction
var (name, age) = person;
Console.WriteLine($"Name: {name}, Age: {age}");
' Tuple declaration
Dim person = (name:= "John", age:= 30)
' Accessing tuple elements
Console.WriteLine($"Name: {person.name}, Age: {person.age}")
' Tuple deconstruction
'INSTANT VB TODO TASK: VB has no equivalent to C# deconstruction declarations:
var(name, age) = person
Console.WriteLine($"Name: {name}, Age: {age}")
VB   C#

Benefits Tuples

Concise Syntax

Tuples allow you to express complex data structures using a concise syntax without the need for defining custom classes or structs.

Lightweight

Tuples are lightweight data structures, making them suitable for scenarios where you need temporary or intermediate storage of data.

Implicit Naming

With tuple syntax, you can implicitly name tuple elements, enhancing code readability and reducing the need for comments.

Returning Multiple Values from Methods

public (int, int) Divide(int dividend, int divisor)
{
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return (quotient, remainder);
}
var result = Divide(10, 3);
Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}");
public (int, int) Divide(int dividend, int divisor)
{
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return (quotient, remainder);
}
var result = Divide(10, 3);
Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}");
Public Function Divide(ByVal dividend As Integer, ByVal divisor As Integer) As (Integer, Integer)
	Dim quotient As Integer = dividend \ divisor
	Dim remainder As Integer = dividend Mod divisor
	Return (quotient, remainder)
End Function
Private result = Divide(10, 3)
Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}")
VB   C#

Simplifying Method Signatures

public (string, string) GetNameAndSurname()
{
    // Retrieve name and surname from a data source
    return ("John", "Doe");
}
var (name, surname) = GetNameAndSurname();
Console.WriteLine($"Name: {name}, Surname: {surname}");
public (string, string) GetNameAndSurname()
{
    // Retrieve name and surname from a data source
    return ("John", "Doe");
}
var (name, surname) = GetNameAndSurname();
Console.WriteLine($"Name: {name}, Surname: {surname}");
Public Function GetNameAndSurname() As (String, String)
	' Retrieve name and surname from a data source
	Return ("John", "Doe")
End Function
'INSTANT VB TODO TASK: VB has no equivalent to C# deconstruction declarations:
var(name, surname) = GetNameAndSurname()
Console.WriteLine($"Name: {name}, Surname: {surname}")
VB   C#
var point = (x: 10, y: 20);
var color = (r: 255, g: 0, b: 0);
var person = (name: "Alice", age: 25);
var point = (x: 10, y: 20);
var color = (r: 255, g: 0, b: 0);
var person = (name: "Alice", age: 25);
Dim point = (x:= 10, y:= 20)
Dim color = (r:= 255, g:= 0, b:= 0)
Dim person = (name:= "Alice", age:= 25)
VB   C#

Limitations and Considerations

While C# 7.0 tuples provide significant benefits, there are some limitations and considerations to keep in mind:

  • Tuples are limited in terms of expressiveness compared to custom classes or structs.
  • Tuple elements are accessed using Item1, Item2, etc. when explicit names are not provided, which can reduce code readability.

Pair Custom Class

public class Pair<T1, T2>
{
    public T1 First { get; set; }
    public T2 Second { get; set; }
    public Pair(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }
}
public class Pair<T1, T2>
{
    public T1 First { get; set; }
    public T2 Second { get; set; }
    public Pair(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }
}
Public Class Pair(Of T1, T2)
	Public Property First() As T1
	Public Property Second() As T2
	Public Sub New(ByVal first As T1, ByVal second As T2)
		Me.First = first
		Me.Second = second
	End Sub
End Class
VB   C#

Here the types are defined at the time of usage and the two properties are exposed as public pain properties

Using the Pair Class

Now, let's explore some common use cases in the following example where the Pair class can be beneficial:

1. Storing Coordinates

Pair<int, int> coordinates = new Pair<int, int>(10, 20); // new instance
Console.WriteLine($"X: {coordinates.First}, Y: {coordinates.Second}");
Pair<int, int> coordinates = new Pair<int, int>(10, 20); // new instance
Console.WriteLine($"X: {coordinates.First}, Y: {coordinates.Second}");
Dim coordinates As New Pair(Of Integer, Integer)(10, 20) ' new instance
Console.WriteLine($"X: {coordinates.First}, Y: {coordinates.Second}")
VB   C#

2. Returning Multiple Values from a Method

public Pair<int, int> Divide(int dividend, int divisor)
{
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return new Pair<int, int>(quotient, remainder);
}
Pair<int, int> result = Divide(10, 3);
Console.WriteLine($"Quotient: {result.First}, Remainder: {result.Second}");
public Pair<int, int> Divide(int dividend, int divisor)
{
    int quotient = dividend / divisor;
    int remainder = dividend % divisor;
    return new Pair<int, int>(quotient, remainder);
}
Pair<int, int> result = Divide(10, 3);
Console.WriteLine($"Quotient: {result.First}, Remainder: {result.Second}");
Public Function Divide(ByVal dividend As Integer, ByVal divisor As Integer) As Pair(Of Integer, Integer)
	Dim quotient As Integer = dividend \ divisor
	Dim remainder As Integer = dividend Mod divisor
	Return New Pair(Of Integer, Integer)(quotient, remainder)
End Function
Private result As Pair(Of Integer, Integer) = Divide(10, 3)
Console.WriteLine($"Quotient: {result.First}, Remainder: {result.Second}")
VB   C#

3. Storing Key-Value Pairs

Pair<string, int> keyValue = new Pair<string, int>("Age", 30);
Console.WriteLine($"Key: {keyValue.First}, Value: {keyValue.Second}");
Pair<string, int> keyValue = new Pair<string, int>("Age", 30);
Console.WriteLine($"Key: {keyValue.First}, Value: {keyValue.Second}");
Dim keyValue As New Pair(Of String, Integer)("Age", 30)
Console.WriteLine($"Key: {keyValue.First}, Value: {keyValue.Second}")
VB   C#

Key-value pairs

Key-value pairs provide a simple and efficient way to associate data. In C#, the primary tool for working with key-value pairs is the Dictionary<TKey, TValue> class, a versatile and powerful collection type

Understanding Key-Value Pairs

A key-value pair is a data structure that associates a unique key with a value. This association allows for efficient retrieval and manipulation of data based on its unique identifier. In C#, key-value pairs are commonly used for tasks such as caching, configuration management, and data storage.

Dictionary<TKey, TValue> in C#

The Dictionary<TKey, TValue> class in C# is a generic collection that stores key-value pairs. It provides fast lookups based on the keys and is widely used for managing associative data.

Creating and Populating a Dictionary

Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Alice"] = 30;
ages["Bob"] = 35;
ages["Charlie"] = 25;
Dictionary<string, int> ages = new Dictionary<string, int>();
ages["Alice"] = 30;
ages["Bob"] = 35;
ages["Charlie"] = 25;
Dim ages As New Dictionary(Of String, Integer)()
ages("Alice") = 30
ages("Bob") = 35
ages("Charlie") = 25
VB   C#

Accessing Values by Key

Console.WriteLine($"Alice's age: {ages["Alice"]}");
Console.WriteLine($"Alice's age: {ages["Alice"]}");
Console.WriteLine($"Alice's age: {ages("Alice")}")
VB   C#

Iterating Over Key-Value Pairs

foreach (var pair in ages)
{
    Console.WriteLine($"Name: {pair.Key}, Age: {pair.Value}");
}
foreach (var pair in ages)
{
    Console.WriteLine($"Name: {pair.Key}, Age: {pair.Value}");
}
For Each pair In ages
	Console.WriteLine($"Name: {pair.Key}, Age: {pair.Value}")
Next pair
VB   C#

Advanced Scenarios

Handling Missing Keys

if (ages.TryGetValue("David", out int age))
{
    Console.WriteLine($"David's age: {age}");
}
else
{
    Console.WriteLine("David's age is not available.");
}
if (ages.TryGetValue("David", out int age))
{
    Console.WriteLine($"David's age: {age}");
}
else
{
    Console.WriteLine("David's age is not available.");
}
Dim age As Integer
If ages.TryGetValue("David", age) Then
	Console.WriteLine($"David's age: {age}")
Else
	Console.WriteLine("David's age is not available.")
End If
VB   C#

Removing Entries

ages.Remove("Charlie");
ages.Remove("Charlie");
ages.Remove("Charlie")
VB   C#

Dictionary Initialization

var colors = new Dictionary<string, string>
{
    { "red", "#FF0000" },
    { "green", "#00FF00" },
    { "blue", "#0000FF" }
};
var colors = new Dictionary<string, string>
{
    { "red", "#FF0000" },
    { "green", "#00FF00" },
    { "blue", "#0000FF" }
};
Dim colors = New Dictionary(Of String, String) From {
	{"red", "#FF0000"},
	{"green", "#00FF00"},
	{"blue", "#0000FF"}
}
VB   C#

Beyond Dictionary: Alternatives and Considerations

While Dictionary<TKey, TValue> is a powerful tool, alternative approaches, and considerations depend on the specific requirements of your application:

  • ConcurrentDictionary<TKey, TValue>: If your application requires thread-safe access to the dictionary from multiple threads, consider using ConcurrentDictionary<TKey, TValue>.
  • ImmutableDictionary<TKey, TValue>: For scenarios where immutability is desired, ImmutableDictionary<TKey, TValue> from the System.Collections.Immutable namespace provides immutable key-value collections.
  • Custom Key-Value Pair Classes: In situations where you need additional functionality or specific behavior, consider creating custom key-value pair classes tailored to your requirements.

IronPDF Library

IronPDF from Iron Software is an excellent library for generating PDF documents. Its ease of use and efficiency are second to none.

IronPDF can be installed from the NuGet package manager:

Install-Package IronPdf

Or from Visual Studio like so:

C# Pair Class (How It Works For Developers): Figure 1 - Installing IronPDF with the NuGet package manager

To generate a document with a tuple example we can use the following code:

namespace IronPatterns;
class Program
{
    static void Main()
    {
        Console.WriteLine("-----------Iron Software-------------");
        var renderer = new ChromePdfRenderer(); // var pattern
        var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
        content += "<h2>Demo C# Pair with Tuples</h2>";
        var result = Divide(10, 3);
        Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}");
        content += $"<p>When we divide 10, 3 </p>";
        content += $"<p>Quotient: {result.Item1}, Remainder: {result.Item2}</p>";
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs("output.pdf"); // Saves PDF        
    }
    public static (int, int) Divide(int dividend, int divisor)
    {
        // var count;
        int quotient = dividend / divisor;
        int remainder = dividend % divisor;
        return (quotient, remainder);
    }
}
namespace IronPatterns;
class Program
{
    static void Main()
    {
        Console.WriteLine("-----------Iron Software-------------");
        var renderer = new ChromePdfRenderer(); // var pattern
        var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
        content += "<h2>Demo C# Pair with Tuples</h2>";
        var result = Divide(10, 3);
        Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}");
        content += $"<p>When we divide 10, 3 </p>";
        content += $"<p>Quotient: {result.Item1}, Remainder: {result.Item2}</p>";
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs("output.pdf"); // Saves PDF        
    }
    public static (int, int) Divide(int dividend, int divisor)
    {
        // var count;
        int quotient = dividend / divisor;
        int remainder = dividend % divisor;
        return (quotient, remainder);
    }
}
Namespace IronPatterns
	Friend Class Program
		Shared Sub Main()
			Console.WriteLine("-----------Iron Software-------------")
			Dim renderer = New ChromePdfRenderer() ' var pattern
			Dim content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!"
			content &= "<h2>Demo C# Pair with Tuples</h2>"
			Dim result = Divide(10, 3)
			Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}")
			content &= $"<p>When we divide 10, 3 </p>"
			content &= $"<p>Quotient: {result.Item1}, Remainder: {result.Item2}</p>"
			Dim pdf = renderer.RenderHtmlAsPdf(content)
			pdf.SaveAs("output.pdf") ' Saves PDF
		End Sub
		Public Shared Function Divide(ByVal dividend As Integer, ByVal divisor As Integer) As (Integer, Integer)
			' var count;
			Dim quotient As Integer = dividend \ divisor
			Dim remainder As Integer = dividend Mod divisor
			Return (quotient, remainder)
		End Function
	End Class
End Namespace
VB   C#

Output

C# Pair Class (How It Works For Developers): Figure 2

Trial License for IronPDF

IronPDF. Place the license in the appsettings.json.

"IronPDF.LicenseKey": "<Your Key>"
"IronPDF.LicenseKey": "<Your Key>"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'"IronPDF.LicenseKey": "<Your Key>"
VB   C#

Conclusion

In this article, we've explored the concept of pairs and the importance of having a Pair class in C#. We've provided a simple implementation of the Pair Custom class along with various use cases demonstrating its versatility and utility in everyday programming tasks.

Whether you're working with coordinates, returning multiple values from a method, or storing key-value associations, the Pair class can be a valuable addition to your programming skill set.

In addition to this IronPDF library is a great combination skill set to have for developers to generate PDF documents on the fly as required in the applications.

< PREVIOUS
Internal Keyword C# (How It Works For Developers)
NEXT >
Dapper C# (How It Works For Developers)

Ready to get started? Version: 2024.10 just released

Free NuGet Download Total downloads: 10,912,787 View Licenses >