教程:在 C 中创建类型#

本教程介绍如何在 C# 中创建类型。 你将编写少量的代码,然后编译并运行这些代码。 本教程包含一系列探索 C# 中不同类型的课程。 这些课程介绍了 C# 语言的基础知识。

前面的教程使用的是文本和数字。 字符串和数字是 简单的类型:它们每个存储一个值。 随着程序规模的扩大,需要使用更为复杂的数据结构。 在需要具有更多字段、属性或行为的数据结构时,C# 提供了可以定义的不同类型。 现在开始探讨这些类型。

在本教程中,你将:

  • 创建和操作元组类型。
  • 创建记录类型。
  • 了解结构、类和接口类型。

先决条件

您必须拥有以下之一:

若要使用 codespaces,需要一个 GitHub 帐户。 如果还没有帐户,可以在 GitHub.com 创建免费帐户。

元组

若要使用教程环境启动 GitHub Codespace,请打开 教程 codespace 存储库的浏览器窗口。 选择绿色 “代码 ”按钮和 “代码空间 ”选项卡。然后选择该 + 符号以使用此环境创建新的 Codespace。 如果已完成本系列中的其他教程,则可以打开该代码空间,而不是创建新的代码空间。

  1. 加载代码空间时,在名为 tuples.cs教程文件夹中创建新文件。

  2. 打开新文件。

  3. 将以下代码键入或复制到 tuples.cs

    var pt = (X: 1, Y: 2);
    
    var slope = (double)pt.Y / (double)pt.X;
    Console.WriteLine($"A line from the origin to the point {pt} has a slope of {slope}.");
    
  4. 通过在集成终端窗口中键入以下命令来运行程序:

    cd tutorials
    dotnet tuples.cs
    

    元组是具有固定长度的有序数值序列。 元组的每个元素都有一个类型和一个可选名称。

    小提示

    在探索 C#(或任何编程语言)的过程中,可能会在编写代码时犯错。 编译器会发现这些错误并向你报告。 当输出包含错误消息时,请仔细查看示例代码和代码以查看要修复的内容。 你还可以要求科皮洛特找出差异或发现任何错误。 该练习有助于学习 C# 代码的结构。

  5. 在前面的代码后面添加以下代码以修改元组成员:

    pt.X = pt.X + 5;
    Console.WriteLine($"The point is now at {pt}.");
    
  6. 还可以使用 with 表达式来创建一个新元组,它是原始元组的修改副本。 在现有代码之后添加以下代码,并在终端窗口中键入 dotnet tuples.cs 以查看结果:

    var pt2 = pt with { Y = 10 };
    Console.WriteLine($"The point 'pt2' is at {pt2}.");
    

    元组 pt2 包含 Xpt 值 (6),而 pt2.Y 是 10。 元组是结构类型。 换言之,元组类型没有 stringint 这样的名称。 元组类型由成员数(称为 arity)和这些成员的类型定义。 成员姓名是为了方便起见。 即使成员具有不同的名称,也可以将元组赋值给具有相同算式和类型的元组。

  7. 可以在编写代码后添加以下代码:

    var subscript = (A: 0, B: 0);
    subscript = pt;
    Console.WriteLine(subscript);
    
  8. 通过在终端窗口中键入 dotnet tuples.cs 来试用它。 变量 subscript 有两个成员,两者均为整数。 两者 subscriptpt 表示同一元组类型的实例:一个包含两个 int 成员的元组。

    元组很容易创建:可以声明多个用括号括起来的成员。 以下所有声明都定义了具有不同元数和成员类型的不同元组。

  9. 添加以下代码以创建新的元组类型:

    var namedData = (Name: "Morning observation", Temp: 17, Wind: 4);
    var person = (FirstName: "", LastName: "");
    var order = (Product: "guitar picks", style: "triangle", quantity: 500, UnitPrice: 0.10m);
    
  10. 通过在终端窗口中再次键入 dotnet tuples.cs 来尝试此更改。

虽然元组易于创建,但它们的功能有限。 元组类型没有名称,因此无法向值集传达含义。 元组类型不能添加行为。 当类型定义了行为时,C# 还可以创建其他类型。

创建记录类型

如果需要在同一结构中使用多个值,元组是个不错的选择。 它们是轻量级的,可以在使用它们时定义它们。 随着你的程序规模扩大,你可能会发现整个代码都在使用相同的元组类型。 如果你的应用在 2D 图形空间中工作,则表示点的元组可能很常见。 找到此模式时,可以声明 record 存储这些值并提供更多功能的类型。

  1. 添加以下代码来声明和使用record类型来表示Point

    public record Point(int X, int Y);
    

    上述代码必须位于源文件的底部。 类型声明(如 record 声明)必须遵循基于文件的应用中的可执行语句。

  2. 在声明前面 record 添加以下代码:

    Point pt3 = new Point(1, 1);
    var pt4 = pt3 with { Y = 10 };
    Console.WriteLine($"The two points are {pt3} and {pt4}");
    

    record 声明是 Point 类型的一行代码,它将 XY 值存储在只读属性中。 只要使用该类型,就必须使用 Point 名称。 正确命名的类型(如 Point)会提供有关如何使用该类型的信息。 其他代码演示如何使用 with 表达式创建新点,该点是现有点的修改副本。 pt4 = pt3 with { Y = 10 } 行中写道:“除了 pt4 被赋值为 10 之外,pt3 的值与 Y 相同”。可以在一个 with 表达式中添加任意数量要更改的属性。

    前面的 record 声明是一行以结尾 ;的代码。 可以通过声明record 类型添加行为。 记录成员可以是函数或更多数据元素。 一个类型的成员在类型声明中,位于 {} 字符之间。

  3. 删除;,并在record声明后添加以下代码行:

    {
        public double Slope() => (double)Y / (double)X;
    }
    
  4. record 声明之前,with 表达式所在行之后添加以下代码:

    double slopeResult = pt4.Slope();
    Console.WriteLine($"The slope of {pt4} is {slopeResult}");
    
  5. 在终端窗口中键入 dotnet tuples.cs 以运行此版本。

    你为代表 X 值的Y添加了格式。 你将record定义为一个命名类型,并且包含一个成员用于计算斜率。 record 类型是 record class 的简写: 包含额外行为的 class 类型。

  6. 也可以修改 Point 类型,使其成为 record struct

    public record struct Point(int X, int Y)
    

    record struct 是一种 struct 类型,包含添加到所有 record 类型中的额外行为。

  7. 通过在终端窗口中键入内容 dotnet tuples.cs 来试用此版本。

结构、类和接口类型

C# 中的所有具体命名类型都是 class 类型或 struct 类型,包括 record 类型。 class引用类型struct 是一个值类型。 值类型的变量在内存中内联存储实例的内容。 换言之,record struct Point 存储了两个整数:XY。 引用类型的变量存储指向实例存储空间的引用或指针。 换言之,record class Point 存储的是对内存块的引用,该内存块保存了 XY 的值。

实际上,这意味着值类型在分配时会被复制,但类实例的副本就是引用的副本。 复制的引用指向同一个点的实例,XY 的存储空间相同。

record 修改器指示编译器为你编写多个成员。 可以在基础知识部分的记录类型一文中了解更多信息。

在声明一个 record 类型时,你就声明了自己的类型应该使用一组默认行为来进行等价比较、赋值和复制该类型的实例。 当存储相关数据是你的类型的主要责任时,记录是最好的选择。 在添加更多行为时,请考虑使用 structclass 类型,而不使用 record 修饰符。

当需要更复杂的功能时,可以对值类型使用 struct 类型,但其主要作用是存储值。 使用 class 类型使用面向对象的成语,如封装、继承和多态性。

还可以定义 interface 类型来声明不同类型必须实现的行为合约。 structclass 类型都可以实现接口。

你通常会在大型程序和程序库中使用所有这些类型。 在安装 .NET SDK 后,可以使用基础知识部分的教程来探索这些类型。

已完成“在 C# 中创建类型”教程。 可以在以下文章中了解有关 C# 中类型的详细信息:

清理资源

GitHub 会在 30 天不活动后自动删除 Codespace。 如果打算探索本系列中的更多教程,您可以保留 Codespace 配置。 如果已准备好访问 .NET 站点 来下载 .NET SDK,则可以删除 Codespace。 若要删除 Codespace,请打开浏览器窗口并导航到 Codespaces。 应该会在窗口中看到代码空间的列表。 在学习教程代码空间的条目中选择三个点(...),然后选择 “删除”。

后续步骤