关于C#:公共字段与自动属性

Public Fields versus Automatic Properties

我们经常被告知,我们应该通过为类字段生成getter和setter方法(C中的属性)来保护封装,而不是将字段暴露给外部世界。

但有很多时候,一个字段只是在那里保存一个值,不需要任何计算来获取或设置。对于这些,我们都会做这个数字:

1
2
3
4
5
6
7
8
9
10
public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

嗯,我有一个忏悔,我不能忍受写所有这些(真的,它不必写,它必须看),所以我去了流氓和使用公共领域。

接下来是C 3.0,我看到它们添加了自动属性:

1
2
3
4
public class Book
{
    public string Title {get; set;}
}

哪一个更整洁,我很感激,但是,真的,有什么不同于仅仅建立一个公共领域?

1
2
3
4
public class Book
{
    public string Title;
}


在我之前的一个相关问题中,有一个链接指向杰夫博客上的一篇文章,解释了一些不同之处。

属性与公共变量

  • 反射在变量和属性上的工作方式不同,所以如果您依赖于反射,则更容易使用所有属性。
  • 不能对变量进行数据绑定。
  • 将变量更改为属性是一种破坏性的更改。例如:

    1
    TryGetTitle(out book.Title); // requires a variable


忽略API问题,我发现使用属性最有价值的是调试。

clr调试器不支持数据断点(大多数本机调试器都支持)。因此,不可能在类的特定字段的读或写上设置断点。在某些调试场景中,这是非常有限的。

因为属性是作为非常瘦的方法实现的,所以可以在其值的读写上设置断点。这使他们在田野上有了一条腿。


从字段更改为属性会破坏合同(例如,需要重新编译所有引用代码)。因此,当您与其他类(任何公共(和一般受保护的)成员)有一个交互点时,您需要为将来的增长做计划。始终使用属性来执行此操作。

今天让它成为一个汽车属性是没有意义的,3个月后你会意识到你想让它懒惰地加载,并在getter中设置一个空检查。如果您使用了字段,则这最多是一个重新编译更改,最坏是不可能的更改,这取决于谁和其他什么依赖于您的程序集。


只是因为没人提到:您不能在接口上定义字段。因此,如果必须实现一个定义属性的特定接口,自动属性有时是一个非常好的特性。


一个巨大的差异,往往被忽视,并没有提到任何其他的答案:压倒性。可以声明虚拟属性并重写它们,但不能对公共成员字段执行相同的操作。


与公共字段相比,自动实现的属性的另一个优点是,您可以将set访问器设置为私有或受保护的,从而为定义了它的对象类提供比公共字段更好的控制。


制作字段public没有任何错误。但是记住,使用private字段创建getter/setter不是封装的。在我看来,如果你不关心Property的其他特性,你也可以使用public


这都是关于版本控制和API稳定性的。在版本1中没有区别,但在以后的版本中,如果您决定需要将此属性设置为具有某种类型的错误签入版本2,则不必更改API-除了属性的定义之外,任何地方都不更改代码。


我发现一件非常有用的事情,以及所有的代码和测试原因是,如果它是一个属性与一个字段,那么Visual Studio IDE将向您显示一个属性而不是字段的引用。


如果稍后决定检查标题是否唯一,通过与集合或数据库进行比较,可以在属性中执行此操作,而不更改依赖于该标题的任何代码。

如果只使用一个公共属性,那么您的灵活性就会降低。

在不破坏契约的情况下,额外的灵活性对于我使用属性是最重要的,而且,在我真正需要灵活性之前,自动生成是最有意义的。