C#6自动初始化属性和支持字段的使用

Spo*_*ock 10 .net c# intermediate-language c#-6.0

在C#6之前,属性的初始化不使用支持字段来初始化默认值.在C#6中,它使用支持字段来初始化新的自动初始化属性.

我很好奇为什么在C#6 IL之前使用属性定义进行初始化.这有什么特别的原因吗?或者在C#6之前没有正确实施?

在C#6.0之前

public class PropertyInitialization
{
    public string First { get; set; }

    public string Last { get; set; }

    public PropertyInitialization()
    {
      this.First = "Adam";
      this.Last = "Smith";
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器生成代码(IL表示)

public class PropertyInitialisation
  {
    [CompilerGenerated]
    private string \u003CFirst\u003Ek__BackingField;
    [CompilerGenerated]
    private string \u003CLast\u003Ek__BackingField;

    public string First
    {
      get
      {
        return this.\u003CFirst\u003Ek__BackingField;
      }
      set
      {
        this.\u003CFirst\u003Ek__BackingField = value;
      }
    }

    public string Last
    {
      get
      {
        return this.\u003CLast\u003Ek__BackingField;
      }
      set
      {
        this.\u003CLast\u003Ek__BackingField = value;
      }
    }

    public PropertyInitialisation()
    {
      base.\u002Ector();
      this.First = "Adam";
      this.Last = "Smith";
    }
  }
Run Code Online (Sandbox Code Playgroud)

C#6

public class AutoPropertyInitialization
{
    public string First { get; set; } = "Adam";
    public string Last { get; set; } = "Smith";
}
Run Code Online (Sandbox Code Playgroud)

编译器生成代码(IL表示)

public class AutoPropertyInitialization
  {
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string \u003CFirst\u003Ek__BackingField;
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string \u003CLast\u003Ek__BackingField;

    public string First
    {
      get
      {
        return this.\u003CFirst\u003Ek__BackingField;
      }
      set
      {
        this.\u003CFirst\u003Ek__BackingField = value;
      }
    }

    public string Last
    {
      get
      {
        return this.\u003CLast\u003Ek__BackingField;
      }
      set
      {
        this.\u003CLast\u003Ek__BackingField = value;
      }
    }

    public AutoPropertyInitialization()
    {
      this.\u003CFirst\u003Ek__BackingField = "Adam";
      this.\u003CLast\u003Ek__BackingField = "Smith";
      base.\u002Ector();
    }
  } 
Run Code Online (Sandbox Code Playgroud)

Wil*_*Ray 9

我很好奇为什么在C#6 IL之前使用属性定义进行初始化.这有什么特别的原因吗?

因为通过自动属性初始化设置值并在构造函数中设置值是两回事.他们有不同的行为.

回想一下,属性是包含字段的访问器方法.所以这一行:

this.First = "Adam";
Run Code Online (Sandbox Code Playgroud)

相当于:

this.set_First("Adam");
Run Code Online (Sandbox Code Playgroud)

你甚至可以在Visual Studio中看到这个!尝试public string set_First(string value)在类中编写带有签名的方法,并观察编译器抱怨你踩到它的脚趾.

就像方法一样,这些可以在子类中重写.看看这段代码:

public class PropertyInitialization
{
    public virtual string First { get; set; }

    public PropertyInitialization()
    {
        this.First = "Adam";
    }
}

public class ZopertyInitalization : PropertyInitialization
{
    public override string First
    {
        get { return base.First; }
        set
        {
            Console.WriteLine($"Child property hit with the value: '{0}'");
            base.First = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,该行将this.First = "Adam"调用子类中的setter.因为你正在调用一种方法,还记得吗?如果编译器将此方法调用解释为对支持字段的直接调用,则它不会最终调用子setter.编译代码的行为会改变程序的行为.不好!

自动属性是不同的.让我们使用auto-property初始值设定项来改变第一个例子:

public class PropertyInitialization
{
    public virtual string First { get; set; } = "Adam";
}

public class ZopertyInitalization : PropertyInitialization
{
    public override string First
    {
        get { return base.First; }
        set
        {
            Console.WriteLine($"Child property hit with the value: '{0}'");
            base.First = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,将不会调用子类中的setter方法.这是故意的.自动属性初始值设定项用于直接设置支持字段.它们的外观和行为类似于字段初始化程序,这就是为什么我们甚至可以在没有setter的属性上使用它们,如下所示:

public string First { get; } = "Adam";
Run Code Online (Sandbox Code Playgroud)

这里没有setter方法!我们必须直接访问支持字段才能执行此操作.自动属性允许程序员创建不可变值,同时仍然可以从良好的语法中受益.