C# 设置器为空的属性是否会占用内存空间?
在下面的三个属性中,是否只有C# 设置器为空的属性是否会占用内存空间?,c#,C#,在下面的三个属性中,是否只有BarProp需要每个类实例4字节的内存 class Foo { int BarEmptySet { get { return 0; } set { } } int BarNoSet { get { return 0; } } int BarProp { get; set; } } 据我所知,属性实际上是“sugar”,它将类的字段包装在两个方法中:默认情况下是getter和setter 但是,它也可以描述非变量值,如常量、函数等。因此,在您
BarProp
需要每个类实例4字节的内存
class Foo
{
int BarEmptySet { get { return 0; } set { } }
int BarNoSet { get { return 0; } }
int BarProp { get; set; }
}
据我所知,属性实际上是“sugar”,它将类的字段包装在两个方法中:默认情况下是getter和setter
但是,它也可以描述非变量值,如常量、函数等。因此,在您的例子中,它将只实例化getter/setter函数,而不实例化所有类实例的后台字段,但最后一个实例将执行其“默认”任务-创建隐藏字段,该字段将占用每个类的内存。,属性实际上是“sugar”,它将类的字段包装在两个方法中:默认情况下是getter和setter
但是,它也可以描述非变量值,如常量、函数等。因此,在您的示例中,它将只实例化getter/setter函数,而不实例化所有类实例的后台字段,但最后一个将执行其“默认值”职责-创建每个类占用内存的隐藏字段。编译器只为(例如
BarProp
)生成一个备份字段。当您提供自定义的get/set实现(例如BarEmptySet
和BarNoSet
)时,不会自动生成备份字段,因此它们本身不会对对象的内存占用做出贡献
这可以通过查看生成的:
BarEmptySet:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
BarNoSet:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
BarProp:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
//getter
IL_0000:ldarg.0
IL_0001:ldfld UserQuery+Foo.k_ubackingfield
IL_0006:ret
//塞特
IL_0000:ldarg.0
IL_0001:ldarg.1
IL_0002:stfld UserQuery+Foo.k__BackingField
IL_0007:ret
如您所见,只有
BarProp
使用stfld
设置支持字段,并使用ldfld
返回支持字段的值。其他人只使用文本0
编译器只为其生成一个支持字段(例如BarProp
)。当您提供自定义的get/set实现(例如BarEmptySet
和BarNoSet
)时,不会自动生成备份字段,因此它们本身不会对对象的内存占用做出贡献
这可以通过查看生成的:
BarEmptySet:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
BarNoSet:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
BarProp:
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// setter
IL_0000: nop
IL_0001: ret
// getter
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
// no setter is generated
// getter
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+Foo.<BarProp>k__BackingField
IL_0006: ret
// setter
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+Foo.<BarProp>k__BackingField
IL_0007: ret
//getter
IL_0000:ldarg.0
IL_0001:ldfld UserQuery+Foo.k_ubackingfield
IL_0006:ret
//塞特
IL_0000:ldarg.0
IL_0001:ldarg.1
IL_0002:stfld UserQuery+Foo.k__BackingField
IL_0007:ret
如您所见,只有
BarProp
使用stfld
设置支持字段,并使用ldfld
返回支持字段的值。其他人只是使用字面的0
为什么你会怀疑它的行为与你所建议的不同?我想说,对这个问题的早期回答证明了它的存在。一个人说IL为每个实例中的所有3个属性加载一个int;下一个人没有。我不知道这个问题的答案,所以我问。ILSpy或类似的内省工具是你的朋友。为什么你会怀疑它的行为与你所说的不同?我想说,对这个问题的早期回答证明了它的存在。一个人说IL为每个实例中的所有3个属性加载一个int;下一个人没有。我不知道这个问题的答案,所以我问。ILSpy或类似的自省工具是你的朋友。答案应该包括证据,例如指向文档的链接或类的编译IL。答案应该包括证据,例如,指向文档的链接或类的已编译IL。我认为只有在没有显式setter或getter时,它们才被称为自动属性。(所以从技术上讲,总是会为自动属性创建一个支持字段)@realbart感谢您发现了这一点,我更新了答案:)我认为只有在没有显式setter或getter的情况下,它们才被称为自动属性。(因此,从技术上讲,总是会为汽车属性创建一个支持字段)@realbart感谢您发现了这一点,我更新了答案:)