0Pricing
C# Academy · 课时

记录类型:基础与语法

声明记录类和记录结构,了解位置语法,并比较记录与类。

记录类型:基础与语法 是 CoddyKit 上的免费 C# Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

什么是记录类型

记录(在 C# 9 中引入)是为具有值语义的不可变数据而设计的引用类型。它们会根据属性值自动生成相等性逻辑和可读的 ToString(),并支持通过 with 表达式进行非破坏性修改。

位置参数记录语法

位置参数语法是最简洁的形式。属性、构造函数、解构和相等性逻辑都可以由一行代码自动生成。

// All in one line:
public record Point(double X, double Y);
public record Person(string FirstName, string LastName, int Age);

// Generated automatically:
// - Primary constructor: new Point(1.0, 2.0)
// - Deconstruct: var (x, y) = point;
// - Equality: p1 == p2 compares X and Y values
// - ToString: "Point { X = 1, Y = 2 }"

记录与类

记录和类的主要区别在于默认的相等性逻辑和设计意图。记录使用结构相等性(基于值),类使用引用相等性(基于身份)。

var p1 = new Point(1, 2);
var p2 = new Point(1, 2);
var p3 = p1;

// Record: structural equality
Console.WriteLine(p1 == p2); // True — same values
Console.WriteLine(p1 == p3); // True — same values

// Compare with a class:
var c1 = new PointClass(1, 2);
var c2 = new PointClass(1, 2);
Console.WriteLine(c1 == c2); // False — different references

记录结构

C# 10 新增了 record struct——一种值类型记录。它们具有与记录类相同的相等性和 ToString 特性,但会像结构一样分配在栈上。

// Record struct: value type, stack-allocated
public record struct Color(byte R, byte G, byte B);

var red   = new Color(255, 0, 0);
var red2  = new Color(255, 0, 0);
Console.WriteLine(red == red2); // True — value equality

// Readonly record struct: fully immutable
public readonly record struct Coord(double Lat, double Lng);

带主体的标准记录声明

记录可以包含完整主体:在保留自动生成的相等性和 ToString 的同时,还可以添加计算属性、方法,并在构造函数中进行验证。

public record Person(string FirstName, string LastName)
{
    // Computed property
    public string FullName => $"{FirstName} {LastName}";

    // Validation in constructor
    public Person : this(FirstName, LastName)
    {
        if (string.IsNullOrWhiteSpace(FirstName))
            throw new ArgumentException("FirstName required");
    }

    // Method
    public Person WithUpperCase() =>
        this with { FirstName = FirstName.ToUpper(), LastName = LastName.ToUpper() };
}

记录的继承

记录支持继承。派生记录可以添加更多属性,并参与相同的相等性规则——只有类型和所有值都匹配时,两个记录才相等。

public record Shape(string Color);
public record Circle(string Color, double Radius) : Shape(Color);
public record Rectangle(string Color, double Width, double Height) : Shape(Color);

var c1 = new Circle("red", 5.0);
var c2 = new Circle("red", 5.0);
var r1 = new Rectangle("red", 5.0, 3.0);

Console.WriteLine(c1 == c2); // True
Console.WriteLine(c1 == r1); // False — different types

非位置参数记录属性

记录并不局限于位置参数。您可以混合使用位置参数和手动声明的属性,也可以使用属性初始化器设置默认值。

public record Order
{
    public int Id { get; init; }
    public string CustomerName { get; init; } = "";
    public List<OrderLine> Lines { get; init; } = new();
    public DateTime CreatedAt { get; init; } = DateTime.UtcNow;
    public OrderStatus Status { get; init; } = OrderStatus.Pending;
}

// Initialization:
var order = new Order
{
    Id = 42,
    CustomerName = "Alice"
    // Other props use defaults
};

解构

位置参数记录会自动生成 Deconstruct 方法,并为每个位置参数属性提供 out 参数。这使得记录可以像元组一样进行解包。

public record Point(double X, double Y);

var p = new Point(3.0, 4.0);

// Deconstruction
var (x, y) = p;
Console.WriteLine($"x={x}, y={y}");

// In switch:
string Describe(Point pt) => pt switch
{
    (0, 0) => "Origin",
    (double x, 0) => $"On X-axis at {x}",
    (0, double y) => $"On Y-axis at {y}",
    var (px, py)  => $"Point ({px}, {py})"
};

将记录用作 DTO

记录非常适合用作 API 请求/响应 DTO。它们不可变、可序列化,而且自动生成的相等性逻辑可以简化测试。

// API request/response records
public record CreateProductRequest(
    string Name,
    decimal Price,
    int Stock);

public record ProductResponse(
    int Id,
    string Name,
    decimal Price,
    int Stock,
    DateTime CreatedAt);

// In controller:
app.MapPost("/products", (CreateProductRequest req, ProductService svc) =>
{
    var product = svc.Create(req.Name, req.Price, req.Stock);
    return Results.Created($"/products/{product.Id}",
        new ProductResponse(product.Id, product.Name,
                            product.Price, product.Stock,
                            product.CreatedAt));
});

单元测试中的记录相等性

值相等性使记录非常适合用于单元测试断言。您可以使用 == 或 Assert.Equal 比较预期记录和实际记录,而无需自定义比较器。

[Fact]
public async Task CreateOrder_ReturnsCorrectResponse()
{
    var response = await _client.PostAsJsonAsync("/orders",
        new CreateOrderRequest(CustomerId: 1, ProductId: 5, Quantity: 2));

    var order = await response.Content.ReadFromJsonAsync<OrderResponse>();

    // Simple equality check — no custom IEqualityComparer needed!
    Assert.Equal(
        new OrderResponse(Id: order!.Id, Status: "Pending", Total: 99.98m),
        order);
}

快速检查

C# 记录默认使用什么相等性语义?

总结:记录类型基础

关键要点:

  • 记录默认是具有值(结构)相等性的引用类型
  • 位置参数语法会生成构造函数、解构、相等性逻辑和 ToString
  • record struct(C# 10)是值类型变体
  • 记录支持继承——进行相等性比较时类型也必须匹配
  • 非常适合 DTO、API 契约和单元测试断言
  • 可以在主体块中,在位置参数旁添加计算属性和方法

常见问题解答

「记录类型:基础与语法」课时是免费的吗?

是的 — 「记录类型:基础与语法」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「记录类型:基础与语法」这节课中我会学到什么?

声明记录类和记录结构,了解位置语法,并比较记录与类。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「记录类型:基础与语法」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 记录类型:基础与语法
  2. 使用 init 与 with 实现不可变性
  3. 值相等性与解构
  4. 领域驱动设计中的记录
← 返回 C# Academy