我应该使用字段还是 属性?

Should I use a field or a property?

首先,我看过asking for the difference between fields and properties这个问题,知道它的用途

现在回答我的问题,我想创建一个 属性,我确信 get 和 set 都是空的,所以我做了 get; set;。一切都很好。但现在我意识到我刚刚创建了一个大写名称的 public 字段,它在所有方面都是相同的。

甚至不能说它被使用以便未来的代码不依赖于实现的论点,因为我可以简单地将其设为 属性 并实现 getter 或 setter. 字段的语义和 属性 在其定义的 class 之外是相同的。

所以我的问题是,当 属性 只使用 get;set; 时,我应该使用字段还是 属性?

所以这个:

public IEnumerable<string> Products;

在所有方面都与此相同:

public IEnumerable<string> Products { get; set; }

should I use a field or a property when a property would simply use get;set;?

使用 属性... 出于以下实际原因,以及出于哲学原因,属性公开状态 API,而字段公开状态实现细节。

The semantics of a field and a property are identical outside the class it is defined in.

这不是真的。

  • 差异通过反射可见,这通常非常重要。例如,许多绑定框架不会使用字段,只会使用属性。
  • 您可以通过 ref 传递可变字段,但不能通过 属性 - 因此将字段更改为 属性 会破坏源兼容性。 (当 Products 变为 属性 时,使用 SomeMethod(ref x.Products) 的代码将失效。)
  • 将字段更改为 属性 也会破坏 binary 兼容性,因此如果程序集 X 是针对程序集 Y v1.0 构建的,并且您将字段更改为属性 对于程序集 Y v1.1,则需要重建程序集 X 否则将无法正确执行
  • 如果你有一个可变值类型(请不要这样做)然后当 Location 是一个字段时写 foo.Location.X = 10 是有效的(因为 x.Location 被归类为一个变量)而当 Location 是 属性 时则不是(因为表达式 x.Location 被归类为值)。如果你有一个方法(在你的邪恶可变类型中)改为改变值,那么 foo.Location.DoSomething() 将在两种情况下编译,但有不同的效果。全家同乐。

最好使用 auto-属性 语法,因为它会创建一个带有私有支持字段的 read/write 属性,从而允许您更改实现(从私有标量字段到字典条目或具有其他自定义逻辑的另一个后端),从而从其实现中释放 "class's interface"(与 interface 不同)。

请注意,对于集合成员属性,建议将其设置器设为私有,如下所示:

public IEnumerable<String> Products { get; private set;}

...这样只有包含 class 才能改变它。

另一种选择是 private readonly 字段,在 C# 6 中,您可以将自动实现的属性与 readonly 后备字段一起使用,如下所示:

public IEnumerable<String> Products { get; } = SomeSource.GetProducts();

视情况而定。我更喜欢在字段上使用 属性。您提到 public IEnumerable<string> Products;public IEnumerable<string> Products { get; set; } 相同,但实际上它们不是。在编译期间,属性 将被转换为两种方法(即 get_Products() 和 set_Products())。

属性 的优点是允许您在分配和返回数据之前指定自定义代码,这对于该字段是不可能的。检查下面的例子

public IEnumerable<string> Products
        {
            get
            {
                if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
                {
                    //Return future product
                    return new List<string>();
                }
                else
                {
                    // return current products
                    return new List<string>() { "testing" };
                }
            }
            set
            {
                if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
                {
                    //ignore assign product
                    Products = new List<string>();
                }
                else
                {
                    // add assign product
                    Products = value;
                }
            }
        }