C#中这两个属性之间有区别吗?第一个属性是否只实例化一次,而第二个属性实际上每次访问属性时都会实例化一个新的字符串对象?
public string Property1 { get; } = "Property1";
public string Property2 => "Property2";
答案 0 :(得分:6)
是的,有区别。第一个声明了一个只读属性:
args
这是
的速记/句法糖public string Property1 { get; } = "Property1";
private readonly string $property1 = "Property1";
public string Property1 { get { return $property1; } }
是编译器生成的字段。
第二个用简写的getter声明一个属性:
$property1
这是简写:
public string Property2 => "Property2";
根本没有支持字段。
第二个实际上并不“实例化一个新的字符串对象”,因为字符串是只读的,字符串常量在编译时被实现;它每次都会返回相同的字符串实例。
在这种特殊情况下,您几乎不会注意到差异,因为只有明确查看具有反射的属性的内容才会注意到是否存在支持字段。对计算表达式的非平凡的getter来说,事情变得更有趣了:
public string Property2 { get { return "Property2"; } }
(当然,这是一个人为的例子,但它显示了只读属性和计算属性之间的区别。)
答案 1 :(得分:0)
当您使用以下两个属性编译类时,要向其他答案添加一些信息:
public string ReadOnlyInitialized { get; } = "String A";
public string ReadOnlyLambda => "String B";
为ReadOnlyInitialized
属性
.field private initonly string '<ReadOnlyInitialized>k__BackingField'
// snipped debugger attributes
.property instance string ReadOnlyInitialized()
{
.get instance string ScratchCsConsole.Program::get_ReadOnlyInitialized()
} // end of property Program::ReadOnlyInitialized
.method public hidebysig specialname instance string
get_ReadOnlyInitialized() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld string ScratchCsConsole.Program::'<ReadOnlyInitialized>k__BackingField'
IL_0006: ret
} // end of method Program::get_ReadOnlyInitialized
您可以从Generated IL中看到编译器为您生成了一个支持字段。
此IL是为ReadOnlyLambda
属性生成的:
.property instance string ReadOnlyLambda()
{
.get instance string ScratchCsConsole.Program::get_ReadOnlyLambda()
} // end of property Program::ReadOnlyLambda
.method public hidebysig specialname instance string
get_ReadOnlyLambda() cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: ldstr "String B"
IL_0005: ret
} // end of method Program::get_ReadOnlyLambda
正如您在此版本中所看到的,唯一的区别是字符串现在作为立即加载到堆栈中,而不是从后备字段加载。