在构造期间设置成员的 C# 惯用方法是什么?

What's the C#-idiomatic way to set a member during construction?

我发现自己写了很多看起来像这样的代码:

 new Foo(7, "a");

其中 Foo 看起来像:

 class Foo {
      int bar;
      string baz;
      public Foo(int bar, string baz) {
           this.bar = bar;
           this.baz = baz;
      }
 }

受过 C# 培训的程序员将如何处理此问题?写 this.bar = barthis.baz = baz 可以,但感觉很奇怪。

您可以使用对象初始化语法:

var foo = new Foo() { bar = 7, baz = "a" };

它要求您的字段为 public 并且属性具有 setter。

编译器会将其翻译成如下代码:

var temp = new Foo();
temp.bar = 7;
temp.baz = "1";
var foo = temp;

我会使用属性而不是字段 - 如果您需要向属性添加逻辑,将来修改起来会更容易。

class Foo 
{
      public int Bar { get; private set; }
      public string Baz { get; private set; }

      public Foo()
      {
      }

      public Foo(int bar, string baz) 
      {
           Bar = bar;
           Baz = baz;
      }
}

一个流行的约定是在私有字段名称前加上_前缀,以区别于普通参数名称,例如

class Foo {
      int _bar;
      string _baz;
      public Foo(int bar, string baz) {
           _bar = bar;
           _baz = baz;
      }
 }

那么就不需要使用 this 了。或者,由于您在问题标题中提到了 properties,您可以将这些字段封装在属性中并进行设置:

class Foo {
      int _bar;
      string _baz;
      public Foo(int bar, string baz) {
           Bar = bar;
           Baz = baz;
      }

    public int Bar
    {
        get { return _bar; }
        set { _bar = value; }
    }

    public string Baz
    {
        get { return _baz; }
        set { _baz = value; }
    }
}

由于 C# 有 case-sensitive 个符号名称,this 仍然是不必要的。现在,如果您没有对属性的 get/set 行为做任何比这更复杂的事情,您可以使用 auto-property 语法 :

class Foo {
    public Foo(int bar, string baz) {
           Bar = bar;
           Baz = baz;
      }

    public int Bar { get; set; }

    public string Baz { get; set; }
}

现在,如果您的共同需求是这些属性可以从外部读取 class 但只能从内部设置,您可以将它们设置为只读:

class Foo {
    public Foo(int bar, string baz) {
           Bar = bar;
           Baz = baz;
      }

    public int Bar { get; private set; }

    public string Baz { get; private set; }
}

但是如果您希望它们真正只在构造函数中设置,您可以返回使用字段:

class Foo {
      readonly int _bar;
      readonly string _baz;
      public Foo(int bar, string baz) {
           _bar = bar;
           _baz = baz;
      }

    public int Bar
    {
        get { return _bar; }
    }

    public string Baz
    {
        get { return _baz; }
    }
}