C# 属性总是有备份字段 "behind the scene" 吗?

Do C# properties always have backup fields "behind the scene"?

我知道当我们在 C# 中使用属性时,编译器总是在 CIL 中为它们生成 getters 和 setters(即 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和setters我在说。 根据我的理解,如果 getters 和 setter 被创建 "behind the scenes" 那么也应该从 which/to 创建一个支持字段,其中 getters 和setter get/set 值。 因此,根据前面的示例,我可以使用反射来检查 Test class 的字段,例如:

    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; } }

But since I don't know how to check it, can you please let me know if a backup field always get created (even if we have a simple property with only 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... */ }
}

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