跳至页脚内容
.NET 帮助

C# Init 关键字(开发者用法)

C# 9.0中的init关键字引入了一种定义类属性的新方法,用于创建不可变对象。 在较早版本的C#中,属性通常使用get和set访问器来读取和写入对象字段。 然而,使用init,你可以在对象初始化期间使可写属性仅可写,之后它们将变为只读。

本教程将通过实用示例和场景探索如何使用IronPDF库中的C# init关键字。 您还将了解传统属性设置器(set)与新init-only设置器之间的关键区别。

Init关键字的基本示例

让我们从一个基本示例开始:

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

var person = new Person
{
    FirstName = "Iron",
    LastName = "Dev"
};

// person.FirstName = "Jane";  // This will give a compile-time error.
public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

var person = new Person
{
    FirstName = "Iron",
    LastName = "Dev"
};

// person.FirstName = "Jane";  // This will give a compile-time error.
Public Class Person
	Public Property FirstName() As String
	Public Property LastName() As String
End Class

Private person = New Person With {
	.FirstName = "Iron",
	.LastName = "Dev"
}

' person.FirstName = "Jane";  // This will give a compile-time error.
$vbLabelText   $csharpLabel

C# Init关键字(如何为开发者工作):图1 - IDE由于属性被标记为init-only而抛出错误

在这个示例中,FirstNameLastName被标记为init-only属性。 这意味着它们只能在对象初始化期间被赋值。 对象创建后,尝试更改这些值将导致编译时错误。

为什么使用Init关键字?

使用init关键字的主要原因是在初始化后使对象属性不可变。 传统上,您可以将属性标记为只读以实现不可变性。 然而,您通常需要一个接受所有必要值的构造函数来设置字段,这可能导致构造函数的样板代码。 使用init,您可以使用对象初始值设定项达到相同的目标,而无需编写冗长的构造函数。

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
    // Without using constructor boilerplate for property initialization
}

var person = new Person
{
    FirstName = "John",
    LastName = "Doe"
};
public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
    // Without using constructor boilerplate for property initialization
}

var person = new Person
{
    FirstName = "John",
    LastName = "Doe"
};
Public Class Person
	Public Property FirstName() As String
	Public Property LastName() As String
	' Without using constructor boilerplate for property initialization
End Class

Private person = New Person With {
	.FirstName = "John",
	.LastName = "Doe"
}
$vbLabelText   $csharpLabel

使用Init-Only属性进行对象初始化

使用init可顺利与对象初始值设定项配合使用。 您可以在创建对象时直接定义所需的属性,而无需依赖构造函数来设置值。

public class Point
{
    public int X { get; init; }
    public int Y { get; init; }
}

var point = new Point { X = 10, Y = 20 };

// point.X = 30;  // This will throw a compile-time error
public class Point
{
    public int X { get; init; }
    public int Y { get; init; }
}

var point = new Point { X = 10, Y = 20 };

// point.X = 30;  // This will throw a compile-time error
Public Class Point
	Public Property X() As Integer
	Public Property Y() As Integer
End Class

Private point = New Point With {
	.X = 10,
	.Y = 20
}

' point.X = 30;  // This will throw a compile-time error
$vbLabelText   $csharpLabel

这创建了一个简单的、不可变的Point类型对象。 请注意,XY的值是在初始化时设置的,之后不能修改。

将init与构造函数混合使用

尽管init的主要用例是通过对象初始值设定项进行对象初始化,但如果需要,您仍然可以使用构造函数。 这在强制执行对象创建时的特定属性值时尤其有用。

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}
public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}
Public Class Person
	Public Property FirstName() As String
	Public Property LastName() As String

	Public Sub New(ByVal firstName As String, ByVal lastName As String)
		Me.FirstName = firstName
		Me.LastName = lastName
	End Sub
End Class
$vbLabelText   $csharpLabel

您可以同时使用构造函数和init属性。 这种方法在对象构建后仍然强制不可变性,同时提供了更多的灵活性。

Init相较于Private Set的优势

以前,开发人员使用私有set访问器以限制类外修改属性。

public class Person
{
    public string FirstName { get; private set; }
    public string LastName { get; private set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}
public class Person
{
    public string FirstName { get; private set; }
    public string LastName { get; private set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}
Public Class Person
	Private privateFirstName As String
	Public Property FirstName() As String
		Get
			Return privateFirstName
		End Get
		Private Set(ByVal value As String)
			privateFirstName = value
		End Set
	End Property
	Private privateLastName As String
	Public Property LastName() As String
		Get
			Return privateLastName
		End Get
		Private Set(ByVal value As String)
			privateLastName = value
		End Set
	End Property

	Public Sub New(ByVal firstName As String, ByVal lastName As String)
		Me.FirstName = firstName
		Me.LastName = lastName
	End Sub
End Class
$vbLabelText   $csharpLabel

尽管这种方法有效,但需要构造函数的样板代码来初始化属性。 此外,它允许类本身以后修改属性,这并不总是理想的不可变对象。 init关键字消除了这个问题,因为它仅允许在对象创建时进行初始化,并阻止之后的任何修改。

使用只读字段和Init访问器处理初始化

init关键字可以在对象创建期间初始化字段或属性,之后它们保持不可变。 虽然只读字段提供了不可变性,但init访问器为属性提供了类似的功能。 这是如何通过使用只读字段和init属性来处理不可变性的两种方式:

使用带构造函数的只读字段

在此示例中,我们为firstNamelastName使用只读字段,这些字段在对象构建期间设置。 这些字段只能在构造函数中分配一次,之后不能修改:

public class Person
{
    private readonly string firstName;
    private readonly string lastName;

    public string FirstName => firstName;
    public string LastName => lastName;

    public Person(string firstName, string lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
public class Person
{
    private readonly string firstName;
    private readonly string lastName;

    public string FirstName => firstName;
    public string LastName => lastName;

    public Person(string firstName, string lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
Public Class Person
'INSTANT VB NOTE: The field firstName was renamed since Visual Basic does not allow fields to have the same name as other class members:
	Private ReadOnly firstName_Conflict As String
'INSTANT VB NOTE: The field lastName was renamed since Visual Basic does not allow fields to have the same name as other class members:
	Private ReadOnly lastName_Conflict As String

	Public ReadOnly Property FirstName() As String
		Get
			Return firstName_Conflict
		End Get
	End Property
	Public ReadOnly Property LastName() As String
		Get
			Return lastName_Conflict
		End Get
	End Property

	Public Sub New(ByVal firstName As String, ByVal lastName As String)
		Me.firstName_Conflict = firstName
		Me.lastName_Conflict = lastName
	End Sub
End Class
$vbLabelText   $csharpLabel

使用Init访问器进行初始化

或者,我们可以使用init访问器创建只能在对象创建期间初始化的只读属性,但之后不能更改。 这消除了只读字段的需要,并提供了一种更现代的语法:

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}
public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}
Public Class Person
	Public Property FirstName() As String
	Public Property LastName() As String
End Class
$vbLabelText   $csharpLabel

IronPDF简介

C# Init关键字(如何为开发者工作):图2 - IronPDF:C# PDF库

IronPDF是一个为C#开发人员设计的强大PDF生成和操作库。 它通过将HTML、CSS、图像和其他内容转换为PDF文档来简化PDF操作。 IronPDF具有像素级完美渲染、跨平台支持和集成到.NET项目中的简单性,非常适合需要快速创建高质量PDF的开发人员。 您可以将其用于.NET Core、Framework和Standard,它支持包括Windows、Linux和macOS在内的广泛平台。

案例:使用C# Init关键字与IronPDF

为了在生成PDF的C#项目中创建不可变对象,您可以将init关键字与IronPDF结合使用。 init关键字确保对象在初始化后的完整性,而IronPDF基于该不可变模型处理数据并生成PDF。

请确保在您的项目中正确引用了IronPDF。 您可以通过NuGet安装它:

Install-Package IronPdf

以下是代码示例:

using IronPdf;

public class Person
{
    public int Id { get; init; }
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

public class PDFGenerator
{
    public static void CreatePersonPDF(Person person)
    {
        var htmlContent = $@"
        <html>
        <body>
            <h1>Person Information</h1>
            <p>ID: {person.Id}</p>
            <p>First Name: {person.FirstName}</p>
            <p>Last Name: {person.LastName}</p>
        </body>
        </html>";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs($"Person_{person.Id}.pdf");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var person = new Person
        {
            Id = 1,
            FirstName = "Iron",
            LastName = "Dev"
        };

        PDFGenerator.CreatePersonPDF(person);
    }
}
using IronPdf;

public class Person
{
    public int Id { get; init; }
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

public class PDFGenerator
{
    public static void CreatePersonPDF(Person person)
    {
        var htmlContent = $@"
        <html>
        <body>
            <h1>Person Information</h1>
            <p>ID: {person.Id}</p>
            <p>First Name: {person.FirstName}</p>
            <p>Last Name: {person.LastName}</p>
        </body>
        </html>";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs($"Person_{person.Id}.pdf");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var person = new Person
        {
            Id = 1,
            FirstName = "Iron",
            LastName = "Dev"
        };

        PDFGenerator.CreatePersonPDF(person);
    }
}
Imports IronPdf

Public Class Person
	Public Property Id() As Integer
	Public Property FirstName() As String
	Public Property LastName() As String
End Class

Public Class PDFGenerator
	Public Shared Sub CreatePersonPDF(ByVal person As Person)
		Dim htmlContent = $"
        <html>
        <body>
            <h1>Person Information</h1>
            <p>ID: {person.Id}</p>
            <p>First Name: {person.FirstName}</p>
            <p>Last Name: {person.LastName}</p>
        </body>
        </html>"

		Dim renderer = New ChromePdfRenderer()
		Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
		pdf.SaveAs($"Person_{person.Id}.pdf")
	End Sub
End Class

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim person As New Person With {
			.Id = 1,
			.FirstName = "Iron",
			.LastName = "Dev"
		}

		PDFGenerator.CreatePersonPDF(person)
	End Sub
End Class
$vbLabelText   $csharpLabel

结论

C# Init关键字(如何为开发者工作):图3 - IronPDF许可页面

总之,C#的init关键字允许您在提供对象初始化期间的灵活性的同时创建不可变对象。 它是私有set访问器的更清晰、更安全的替代方案,减少了构造函数样板代码的需求。 将init关键字与只读字段、结构体和验证逻辑结合使用,有助于构建稳健的、可靠的数据结构,同时保持不可变性而不牺牲可读性或灵活性。 IronPDF提供,许可证起价USD$liteLicense。 这允许您访问其全部功能,包括编辑、压缩和保护PDF。

常见问题解答

如何在C#中将HTML转换为PDF?

你可以使用IronPDF的RenderHtmlAsPdf方法将HTML字符串转换为PDF。你还可以使用RenderHtmlFileAsPdf将HTML文件转换为PDF。

C#中init关键字的目的是什么?

init关键字允许您定义仅可在对象初始化期间设定的属性,确保在此之后的不可变性。此功能对于创建不应更改的对象特别有用。

init关键字在C#中如何增强对象的不可变性?

init关键字使属性仅在对象的初始化阶段被设定,防止此后的任何更改。这确保对象在创建后保持不可变。

init属性可以用于PDF生成的库吗?

是的,init属性可以与IronPDF等库一起使用,从不可变对象生成PDF,确保用于PDF生成的数据在整个过程中保持一致。

使用init关键字相比传统setter有什么优势?

使用init关键字相比传统setter促进了不可变性,减少了冗长构造函数代码的需求,并确保对象属性在初始化后不能被修改。

如何在C#中将PDF生成与不可变属性集成?

您可以使用init属性创建不可变对象,并将这些对象传递给IronPDF,后者可以利用这些数据生成一致和可靠的PDF文档。

init关键字在创建现代C#应用中扮演什么角色?

init关键字在创建现代C#应用中扮演了至关重要的角色,使开发者可以以简洁的语法定义不可变对象,提高代码安全性并减少错误。

如何在C#项目中安装PDF生成库?

您可以通过使用NuGet包管理器和以下命令在您的C#项目中安装例如IronPDF这样的库:Install-Package IronPdf

为什么不可变性在应用程序开发中很重要?

不可变性很重要,因为它确保了整个应用程序中的数据完整性和一致性,使维护更容易,并减少错误的可能性。

哪些实用示例说明了init关键字的使用?

一个实用示例是使用init关键字定义一个类,该类的属性仅可在初始化时设定,确保创建的对象保持不变。这在需要数据一致性的情况下特别有用。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。