在 C# 编程领域,数据结构化是编写高效且可维护代码的关键方面。虽然类和结构长期以来一直是组织相关数据的首选选项,但元组已成为一种强大而轻量级的替代方案,尤其是在处理临时和临时数据结构时。在本文中,我们将探讨 C# 中的元组,重点介绍它们与类 DTO(数据传输对象)的区别,研究它们支持的各种返回类型,并深入研究实际用例。
简单来说,元组是一组有序值,通常用于表示相关数据的集合。与数组或列表不同,元组可以包含不同类型的元素,这使得它们对于数据结构是临时的或元素之间的关系至关重要的场景变得灵活和方便。
在 C# 中,元组由结构表示,它们可用于简洁而富有表现力地存储异构数据。System.ValueTuple
C# 提供了多种创建元组的方法:
可以在不显式指定类型的情况下隐式创建元组。编译器将根据提供的值推断类型。
var person = ("John", 30, "Developer");
在此示例中,是一个包含三个元素的元组:一个字符串、一个整数和另一个字符串。person
在声明元组时,可以显式定义元组元素的类型。
Tuple<string, int, string> person = new Tuple<string, int, string>("John", 30, "Developer");
在这里,我们使用该类为每个元素创建一个具有指定类型的元组。Tuple<>
若要访问元组的元素,可以使用点表示法,后跟元素的位置。
Console.WriteLine($"Name: {person.Item1}, Age: {person.Item2}, Occupation: {person.Item3}");
请注意,从 C# 7.0 开始,引入了命名元素,使元组解构更具可读性。
var (name, age, occupation) = person;
Console.WriteLine($"Name: {name}, Age: {age}, Occupation: {occupation}");
C# 中的元组是轻量级数据结构,允许您将多个元素组合成一个不可变的单元。它们是在 C# 7.0 中引入的,它提供了用于定义和使用有序值集的简洁语法。与类不同,元组主要用于临时或短期数据,因此对于成熟的类可能看起来矫枉过正的情况特别有用。
下面是创建和使用元组的基本示例:
var person = ("John", "Doe", 30);
Console.WriteLine($"Name: {person.Item1} {person.Item2}, Age: {person.Item3}");
另一方面,数据传输对象 (DTO) 是设计用于在软件应用程序子系统之间传输数据的类。它们通常用于封装执行特定操作或在应用程序各层之间传输信息所需的数据。与元组不同,DTO 是显式定义的类,允许更结构化和更有条理的数据表示。
下面是一个类 DTO 的简单示例:
public class PersonDTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
// Usage
var person = new PersonDTO { FirstName = "John", LastName = "Doe", Age = 30 };
Console.WriteLine($"Name: {person.FirstName} {person.LastName}, Age: {person.Age}");
总之,元组适用于需要临时轻量级数据结构的场景,而类 DTO 则为长期数据表示和传输提供了更正式和结构化的方法。
元组的优点之一是它们能够在单个返回类型中表示多个值。在元组出现之前,开发人员通常依靠参数、数组或自定义类来实现类似的结果。使用元组,语法变得更加简洁和富有表现力。
public (int, int) DivideAndRemainder(int dividend, int divisor)
{
int quotient = dividend / divisor;
int remainder = dividend % divisor;
return (quotient, remainder);
}
// Usage
var result = DivideAndRemainder(10, 3);
Console.WriteLine($"Quotient: {result.Item1}, Remainder: {result.Item2}");
在上面的示例中,该方法返回一个元组,其中包含除法运算的商和余数。DivideAndRemainder
.NET Framework 直接支持具有 1 到 7 个元素的元组。此外,还可以通过将元组对象嵌套在 Tuple<T1,T2,T3,T4,T5,T6,T7,TRest> 对象的 Rest 属性中来创建包含 8 个或更多元素的元组。
元组在各种实际场景中都能找到自己的位置,尤其是在处理以下问题时:
static (int, int) GetMinMax(int[] numbers)
{
int min = numbers[0];
int max = numbers[0];
foreach (int num in numbers)
{
if (num < min)
min = num;
if (num > max)
max = num;
}
return (min, max);
}
此代码定义一个方法,该方法采用整数数组并返回包含数组中最小值和最大值的元组。该方法使用一个简单的循环来遍历数组,并相应地更新最小值和最大值。GetMinMax
string[] names = { "Alice", "Bob", "Charlie", "David", "Eve" };
var result = names
.Select((name, index) => (name, length: name.Length, index))
.ToList();
在这里,代码使用 LINQ 将数组中的每个名称及其在数组中的长度和索引投影到元组中。该方法用于为数组中的每个元素创建一个新元组,并将结果存储在列表中。Select
var person = (Name: "John", Age: 30);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
此代码片段演示了如何创建元组来表示简单的键值对。在这种情况下,它用于存储有关一个人的信息——他们的姓名和年龄。可以使用命名属性 ( 和 ) 访问元组元素。NameAge
class Person
{
// ... (constructor and other members)
public void Deconstruct(out string first, out string last, out int age)
{
first = FirstName;
last = LastName;
age = Age;
}
}
var person = new Person("John", "Doe", 25);
var (first, last, age) = person;
在此示例中,使用方法定义类。此方法用于解构,允许对象轻松转换为其各个属性的元组。最后一行演示了如何将对象解构为单独的变量。PersonDeconstructPerson
var student = ("Alice", "Smith", 22);
Console.WriteLine($"Name: {student.Item1} {student.Item2}, Age: {student.Item3}");
在这里,元组用于表示有关学生的信息(姓名和年龄)。元组的元素使用默认的 、 等属性进行访问。然后,代码会打印出学生的姓名和年龄。Item1Item2
C# 中的元组提供了一种轻量级且富有表现力的数据结构化方式,尤其是在可能不需要完整类的情况下。虽然类 DTO 为长期数据表示提供了一种更加结构化的方法,但元组在简单性和简洁性是关键的情况下大放异彩。通过了解元组和类 DTO 之间的差异,并了解它们支持的各种返回类型,开发人员可以为手头的任务选择最合适的工具,从而获得更简洁、更易于维护的代码。