C# Record 与 Class(开发人员如何使用)
在 C# 的世界中,主要使用两种结构来建模和封装数据:类和record。 两者都是引用类型,但在其预期用途、行为及处理相等性方式上有显著差异。 本指南将解析这些差异,提供清晰的示例和实用用例,帮助开发人员选择适合他们需求的结构。 我们还将了解IronPDF library。
C# 中的类:基础知识
类是 C# 面向对象编程的基石,旨在封装数据和行为。 它们是引用类型,这意味着具有相同值的两个类实例被视为两个独立的对象。 这种区别在比较两个类实例时至关重要; 默认比较是基于引用的,而不是基于值的。
public class Person
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FullName { get; set; }
}
Public Class Person
Public Property Id() As Integer
Public Property FullName() As String
End Class
在上述示例中,Person 是一个带有 Id 和 FullName 属性的类。 即使两个 Person 实例具有相同的 Id 和 FullName 值,默认情况下它们也不会被认为是相等的,因为它们在内存中是两个不同的引用。
C# 中的 record:不可变数据结构
在 C# 中引入的 record 类型是为了简化不可变数据结构的创建,提供了一个更为强大的替代传统类结构的方法。 与类不同,record 提供基于值的相等性语义,使其非常适合于数据传输对象或行为较少的小型数据结构。
public record Person(int Id, string FullName);
public record Person(int Id, string FullName);
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Person(int Id, string FullName)
在上述示例中,record 定义更简洁,减少了样板代码。 record 自动支持无损变更和基于值的比较。 具有相同值的两个 record 实例被认为是相等的,与值语义对齐。
实用用例:何时使用 record 还是类
在 C# 中选择使用类、record 或其他数据结构,取决于您所建模数据的复杂性以及应用程序所需的行为。 类专为复杂的数据结构设计,支持行为(方法)并允许根据需要修改实例。 而 record 是简单数据结构的完美典范,设计时具有不可变的特性和基于值的相等性,非常适合创建后保持不变的数据。
当您的数据结构需要封装数据和行为或者您需要在创建后操纵数据时,类是理想的。 这种灵活性使类成为大多数传统面向对象编程场景以及构建复杂数据结构的首选。
在数据不可变性至关重要或处理作为数据容器的简单数据结构时,record 更加出色。 它们内置的基于值的相等性和简洁的语法使它们成为数据传输对象或值对象的优秀选择。
值类型和引用类型
理解 C# 中值类型和引用类型的区别至关重要。 类是引用类型,这意味着变量持有指向内存中实际数据的引用。 这种特性导致了默认的基于引用的相等性比较。
record 虽然也是引用类型,但通过其内置的基于值的相等性模拟值语义,使其在比较时表现得有点像值类型。
代码示例:实现类和 record
让我们实现一个类和一个 record,以突出语法和行为上的差异。
类实现:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Product(int id, string name)
{
Id = id;
Name = name;
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Product(int id, string name)
{
Id = id;
Name = name;
}
}
Public Class Product
Public Property Id() As Integer
Public Property Name() As String
Public Sub New(ByVal id As Integer, ByVal name As String)
Me.Id = id
Me.Name = name
End Sub
End Class
record 实现:
public record Product(int Id, string Name);
public record Product(int Id, string Name);
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Product(int Id, string Name)
请注意 record 实现的简洁性和简易性。 record 会自动生成构造函数、属性和用于基于值相等的方法。
理解相等性:引用 vs. 值
C# 中类和 record 类型之间的核心区别确实在于它们如何处理相等性:
-
类默认使用引用相等性,这意味着如果两个实例指向相同的内存位置,它们就是相等的。
- record 默认使用值相等性,当属性具有相同的值时,认为两个实例是相等的。
引用相等性示例(类)
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
var classInstance1 = new Person { Id = 1, Name = "Iron Software" };
var classInstance2 = new Person { Id = 1, Name = "Iron Software" };
Console.WriteLine(classInstance1 == classInstance2); // Outputs: False
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
var classInstance1 = new Person { Id = 1, Name = "Iron Software" };
var classInstance2 = new Person { Id = 1, Name = "Iron Software" };
Console.WriteLine(classInstance1 == classInstance2); // Outputs: False
Public Class Person
Public Property Id() As Integer
Public Property Name() As String
End Class
Private classInstance1 = New Person With {
.Id = 1,
.Name = "Iron Software"
}
Private classInstance2 = New Person With {
.Id = 1,
.Name = "Iron Software"
}
Console.WriteLine(classInstance1 = classInstance2) ' Outputs: False
具有相同属性值的两个类实例不会被认为是相等的,因为它们在内存中是不同的对象。
值相等性示例
public record Person(int Id, string Name);
var recordInstance1 = new Person(1, "Iron Software");
var recordInstance2 = new Person(1, "Iron Software");
Console.WriteLine(recordInstance1 == recordInstance2); // Outputs: True
public record Person(int Id, string Name);
var recordInstance1 = new Person(1, "Iron Software");
var recordInstance2 = new Person(1, "Iron Software");
Console.WriteLine(recordInstance1 == recordInstance2); // Outputs: True
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Person(int Id, string Name)
Private recordInstance1 = New Person(1, "Iron Software")
Private recordInstance2 = New Person(1, "Iron Software")
Console.WriteLine(recordInstance1 = recordInstance2) ' Outputs: True
具有相同属性值的两个 record 实例默认被认为是相等的。
高级功能:record
record 具有若干高级功能,以满足不可变数据结构和基于值相等性的需求。 with 表达式允许通过复制现有 record 并修改某些属性来创建新的 record 实例,展示了无损变更。
使用 record 进行无损变更:
var originalRecord = new Person(1, "Doe");
var modifiedRecord = originalRecord with { Name = "Iron Developer" };
var originalRecord = new Person(1, "Doe");
var modifiedRecord = originalRecord with { Name = "Iron Developer" };
Dim originalRecord = New Person(1, "Doe")
'INSTANT VB TODO TASK: C# 'with expressions' are not converted by Instant VB:
'var modifiedRecord = originalRecord with { Name = "Iron Developer" }
此功能在使用不可变数据结构时非常方便,因为它提供了一种"修改"实例而不更改原始数据的方法。
IronPDF库简介

IronPDF 是一个为 .NET 开发人员提供的 PDF 库,提供了在 .NET 应用程序中直接创建、编辑和管理 PDF 文档的全面解决方案。 通过允许开发人员将 HTML 转换为 PDF、CSS、JavaScript 和图像简化了 PDF 生成过程。 IronPDF 支持多种 .NET 框架和项目类型,包括 Web、桌面和控制台应用程序,跨多个操作系统如 Windows、Linux 和 macOS。
除了创建 PDF,IronPDF 还提供编辑 PDF、设置属性和安全性、处理 PDF 表单和提取内容的功能。 它旨在满足希望将 PDF 功能集成到其 .NET 项目的开发人员的需求。
代码示例
使用 IronPDF 在 C# 中创建 PDF 可以通过类和 record 来实现。 以下是生成简单 PDF 文档的两种方法的示例。 C# 中类和 record 的主要区别在于它们的预期用途:类默认是可变的,设计用于传统的面向对象编程,而 record 是不可变的,设计用于基于值编程,使其非常适合于数据建模。
使用类
在此示例中,我们将定义一个包含从给定 HTML 字符串创建 PDF 方法的PdfGenerator 类。
using IronPdf;
using System;
public class PdfGenerator
{
public string HtmlContent { get; set; }
public PdfGenerator(string htmlContent)
{
HtmlContent = htmlContent;
}
public void GeneratePdf(string filePath)
{
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(HtmlContent);
pdfDocument.SaveAs(filePath);
}
}
class Program
{
public static void Main(string[] args)
{
License.LicenseKey = "License-Key"; // Set your license key here
var generator = new PdfGenerator("<h1>Hello, World from Class!</h1>");
generator.GeneratePdf("ClassExample.pdf");
}
}
using IronPdf;
using System;
public class PdfGenerator
{
public string HtmlContent { get; set; }
public PdfGenerator(string htmlContent)
{
HtmlContent = htmlContent;
}
public void GeneratePdf(string filePath)
{
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(HtmlContent);
pdfDocument.SaveAs(filePath);
}
}
class Program
{
public static void Main(string[] args)
{
License.LicenseKey = "License-Key"; // Set your license key here
var generator = new PdfGenerator("<h1>Hello, World from Class!</h1>");
generator.GeneratePdf("ClassExample.pdf");
}
}
Imports IronPdf
Imports System
Public Class PdfGenerator
Public Property HtmlContent() As String
Public Sub New(ByVal htmlContent As String)
Me.HtmlContent = htmlContent
End Sub
Public Sub GeneratePdf(ByVal filePath As String)
Dim renderer = New ChromePdfRenderer()
Dim pdfDocument = renderer.RenderHtmlAsPdf(HtmlContent)
pdfDocument.SaveAs(filePath)
End Sub
End Class
Friend Class Program
Public Shared Sub Main(ByVal args() As String)
License.LicenseKey = "License-Key" ' Set your license key here
Dim generator = New PdfGenerator("<h1>Hello, World from Class!</h1>")
generator.GeneratePdf("ClassExample.pdf")
End Sub
End Class
输出:

使用 record
相比之下,C# 中的 record 在初始化后是不可变的。 以下是如何使用 with 表达式对 record 进行修改,从而实现类似结果的方法,该方法本质上是返回具有所需更改的 record 的新实例。
using IronPdf;
using System;
public record PdfGeneratorRecord(string HtmlContent)
{
public void GeneratePdf(string filePath)
{
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(this.HtmlContent);
pdfDocument.SaveAs(filePath);
}
}
class Program
{
public static void Main(string[] args)
{
License.LicenseKey = "License-Key"; // Set your license key here
var recordGenerator = new PdfGeneratorRecord("<h1>Hello, World from Record!</h1>");
recordGenerator.GeneratePdf("RecordExample.pdf");
}
}
using IronPdf;
using System;
public record PdfGeneratorRecord(string HtmlContent)
{
public void GeneratePdf(string filePath)
{
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(this.HtmlContent);
pdfDocument.SaveAs(filePath);
}
}
class Program
{
public static void Main(string[] args)
{
License.LicenseKey = "License-Key"; // Set your license key here
var recordGenerator = new PdfGeneratorRecord("<h1>Hello, World from Record!</h1>");
recordGenerator.GeneratePdf("RecordExample.pdf");
}
}
Imports IronPdf
Imports System
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record PdfGeneratorRecord(string HtmlContent)
'{
' public void GeneratePdf(string filePath)
' {
' var renderer = New ChromePdfRenderer();
' var pdfDocument = renderer.RenderHtmlAsPdf(Me.HtmlContent);
' pdfDocument.SaveAs(filePath);
' }
'}
Friend Class Program
Public Shared Sub Main(ByVal args() As String)
License.LicenseKey = "License-Key" ' Set your license key here
Dim recordGenerator = New PdfGeneratorRecord("<h1>Hello, World from Record!</h1>")
recordGenerator.GeneratePdf("RecordExample.pdf")
End Sub
End Class
输出:

这些示例演示了如何使用 IronPDF 在 C# 中通过类和 record 生成 PDF 文件。 选择使用类还是 record 取决于您的具体需求:如果您需要在创建后修改的对象,类可能更合适。 如果您处理的是创建后不应更改的数据,或者您欣赏不可变性的语法简洁性和安全性,record 可能是更好的选择。
结论

总之,类提供传统的面向对象功能,具有可变状态和基于引用的相等性,而 record 提供现代方法来定义具有基于值相等性的不可变数据结构。
在使用类还是 record 之间进行选择时,应根据应用程序的具体要求进行指导,考虑不可变性的需要、数据结构的复杂性以及首选的相等比较方法。 探索 IronPDF 的免费试用版,该版本适用于希望将 PDF 功能集成到其 .NET 应用程序中的用户,许可证价格从 $999 起。
常见问题解答
C# 类和记录的主要区别是什么?
C# 类和记录都是用于建模和封装数据的引用类型,但它们在处理相等性和不变性上有所不同。类使用引用相等性,即当两个实例指向相同的内存位置时,它们被视为相等。另一方面,记录使用值相等性,当两个实例的属性具有相同的值时,它们被视为相等,并设计为默认不可变。
我如何决定在 C# 中使用类还是记录?
在 C# 中选择使用类还是记录取决于您的具体要求。如果您需要可变实例或希望封装面向对象编程中典型的数据和行为,请使用类。如果您的结构简单、不可变,并且您需要基于值的相等性(例如在数据传输对象中),请选择记录。
IronPDF 库如何支持 .NET 中的 PDF 生成?
IronPDF 是一个强大的 .NET PDF 库,可简化 PDF 文档的创建、编辑和管理。它允许开发人员将 HTML、CSS、JavaScript 和图像转换为 PDF,支持各种 .NET Framework和操作系统,使其成为 .NET 开发人员的必备工具。
我可以在 PDF 生成项目中同时使用 C# 类和记录吗?
是的,您可以在 PDF 生成项目中同时使用 C# 类和记录。选择取决于您是否需要用于逻辑的可变或不可变数据结构。例如,IronPDF 可以无缝地使用任一结构生成和处理 PDF。
不变性在 C# 记录中扮演什么角色?
不变性是 C# 记录的核心特性。一旦创建,记录的属性就不能更改,这符合基于值的相等性语义。这种设计使记录在数据一致性和完整性至关重要的场景中成为理想选择,例如在数据传输对象中。
IronPDF 如何增强 .NET 应用程序的 PDF 功能?
IronPDF 通过提供将 HTML 转换为 PDF、编辑 PDF 和管理文档安全性等功能来增强 .NET 应用程序的 PDF 功能。它支持表单操作、内容提取,并无缝集成于不同的 .NET 环境,从而简化 PDF 文档处理。
在 C# 记录的语境下,“with”表达式是什么?
在 C# 记录中,“with”表达式用于无破坏性变异。它允许开发人员通过复制现有记录实例来创建新实例,但某些属性已修改,确保原始数据保持不变。
为什么记录被认为适合数据传输对象?
记录被认为适合数据传输对象,因为它们提供了一种简洁的语法来定义具有基于值的相等性的不可变结构。这确保了数据完整性,并且包含相同值的实例被视为相等,这在数据传输场景中通常是需要的。




