在C# 9中,随着.NET 5的发布,迎来了一个有趣的新关键字:init。这个关键字允许开发者创建不可变对象,至少在标记了init的属性方面是不可变的,从而确保这些属性的值在初始化后不会被改变。本文将深入探讨init关键字的工作原理以及如何使用它。
首先,来看init关键字的基本用法。在声明属性时,可以使用init关键字代替set关键字,如下所示:
class TestClass1
{
public int TestClass1IntProperty { get; set; }
}
class TestClass2
{
public int TestClass2IntProperty { get; init; }
}
在上面的例子中,TestClass1的TestClass1IntProperty属性是可变的,而TestClass2的TestClass2IntProperty属性则是不可变的。
接下来,来看如何使用这些属性:
void Main()
{
TestClass1 test1 = new TestClass1
{
TestClass1IntProperty = 42
};
test1.TestClass1IntProperty = 43; // 这是允许的,因为属性是可变的。
TestClass2 test2 = new TestClass2
{
TestClass2IntProperty = 42
};
// 下面的代码将导致编译错误:
// CS8852 Init-only property or indexer '
如上所示,尝试修改TestClass2的TestClass2IntProperty属性将导致编译错误,因为它是不可变的。
此外,可以在类中只对某些属性使用init关键字,以达到部分不可变的目的,如下所示:
class TestClass3
{
public int TestClass3IntProperty { get; set; }
public int TestClass3IntProperty2 { get; init; }
}
在这种情况下,TestClass3的TestClass3IntProperty属性是可变的,而TestClass3IntProperty2属性则是不可变的。
还可以通过在初始化实例时运行自定义代码来设置属性值,如下所示:
class TestClass4
{
private int _testClass4IntProperty;
public int TestClass4IntProperty
{
get => _testClass4IntProperty;
init => _testClass4IntProperty = value;
}
private int _testClass4IntProperty2;
public int TestClass4IntProperty2
{
get => _testClass4IntProperty2;
init { _testClass4IntProperty2 = value; }
}
}
在这个例子中,TestClass4的TestClass4IntProperty和TestClass4IntProperty2属性在初始化时可以执行自定义代码。
尽管init关键字非常有用,但它也有一些需要注意的事项。例如,如果属性是引用类型,那么它只保持引用,而不是对象本身,这意味着仍然可以修改引用对象的非不可变属性,如下所示:
class TestClass5
{
public int TestClass5IntProperty { get; set; }
}
class TestClass6
{
public TestClass5 TestClass6RefProperty { get; init; }
}
void Main()
{
TestClass6 test = new TestClass6
{
TestClass6RefProperty = new TestClass5
{
TestClass5IntProperty = 42
}
};
test.TestClass6RefProperty.TestClass5IntProperty = 445; // 这是有效的,因为没有改变引用。
test.TestClass6RefProperty = new TestClass5 { TestClass5IntProperty = 13 }; // 这将导致错误,因为试图改变init属性的引用。
}
在这个例子中,尽管TestClass6的TestClass6RefProperty属性是不可变的,但仍然可以修改引用对象的非不可变属性。