C# 属性是否始终"behind the scene"备份字段?



我知道,当我们在 C# 中使用属性时,编译器总是在 CIL 中为它们生成 getter 和 setter(即 get_PropertyName 和 set_PropertyName),例如,考虑以下代码段:

class Program
{
class Test
{
public string Name { get; set; }
}
static void Main(string[] args)
{
//Here I'm using reflection to inspect methods of Test class
Type type = typeof(Test);
foreach (var item in type.GetMethods())
{
Console.WriteLine(item.Name);
}
}
} 

该程序将使用以下方法产生输出Test,其中将有get_Nameset_Name- 我所说的 getter 和 setter。 根据我的理解,如果 getter 和 setter 是在"幕后"创建的,那么也应该创建一个支持字段,getter 和 setter 从中获取/设置值。 因此,从前面的示例中,我可以使用反射来检查 Test 类的字段,如下所示:

static void Main(string[] args)
{
Type type = typeof(Test);
foreach (var item in type.GetFields())
{
Console.WriteLine(item.Name);
}
} 

该程序的输出是空的,我认为这是因为创建的支持字段具有private访问权限,因此我们看不到它。但是由于我不知道如何检查它,您能否让我知道是否总是创建一个支持字段(即使我们有一个只有get;set;的简单属性)?

如果你的意思是简单的属性,如:

{get;set;}

或:

{get;}

那么是的,有一个字段; 将BindingFlags.NonPublic | BindingFlags.Instance添加到您的GetFields()呼叫中,您将看到它:

foreach (var item in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
Console.WriteLine(item.Name);
}

它通常有一个涉及<>的不可发音的名称 - 你的在我的机器上<Name>k__BackingField- 但是:这个名称是一个编译器功能(尽管许多序列化等库使用它,所以它不太可能改变)。

但是:不,属性本身并不总是涉及字段;例如:

public int Value => 42; // no field

public int Name { get { return obj.Name; } set { obj.Name = value; } }
但是

由于我不知道如何检查它,您能否让我知道是否总是创建备份字段(即使我们有一个简单的属性,只有get; and set; ?

自动实现的属性,例如

public int ReadWriteProperty { get; set; }
public int ReadOnlyProperty { get; }

确实总是有一个由编译器生成的支持字段。但是,如果您提供自己的 getter/setter 实现,则编译器不会生成字段:

public int Zero => 0;
public int IgnoresSetter
{
get { return 10; }
set { /* Meh. Whatever you say, I'm still going to return 10 in the getter... */ }
}

这些都不会导致生成字段。

最新更新