公共字段与自动属性

时间:2009-07-25 01:04:49

标签: c# class properties field automatic-properties

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

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

public class Book
{
    private string _title;

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

好吧,我有一个坦白,我不忍心写下所有这些(真的,它不必写它,它不得不看它),所以我去流氓并使用公共领域。

然后是C#3.0,我看到他们添加了自动属性:

public class Book
{
    public string Title {get; set;} 
}

更整洁,我很感激,但是真的,除了创建公共领域之外有什么不同呢?

public class Book
{
    public string Title;
}

12 个答案:

答案 0 :(得分:160)

在我前段时间的related question中,有一条链接指向杰夫博客上的帖子,解释了一些差异。

Properties vs. Public Variables

  • 反射在变量与属性上的工作方式不同,因此如果依赖于反射,则更容易使用所有属性。
  • 您无法对变量进行数据绑定。
  • 将变量更改为属性是一个重大变化。例如:

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

答案 1 :(得分:76)

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

CLR调试器不支持数据断点(大多数本机调试器都支持)。因此,无法在类的特定字段的读取或写入上设置断点。在某些调试方案中,这是非常有限的。

由于属性是以非常精简的方法实现的,因此可以在读取和写入其值时设置断点。这使他们在田野上占了一席之地。

答案 2 :(得分:61)

从字段更改为属性会破坏合同(例如,需要重新编译所有引用代码)。因此,当您与其他类(任何公共(通常受保护的)成员)建立交互点时,您希望计划未来的增长。通过始终使用属性来实现。

今天没有什么可以让它成为一个自动财产,并且3个月后就意识到你想让它延迟加载,并在getter中进行空检查。如果你使用了一个字段,这是一个最好的重新编译更改,最坏的情况是不可能的,这取决于谁和&还有什么依赖于你的装配。

答案 3 :(得分:57)

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

答案 4 :(得分:44)

经常被忽视的巨大差异在任何其他答案中都没有提及:覆盖。您可以声明属性虚拟并覆盖它们,而不能对公共成员字段执行相同的操作。

答案 5 :(得分:10)

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

答案 6 :(得分:8)

制作字段public没有错。但请记住,使用getter/setter字段创建private并不是封装。 IMO,如果您不关心Property的其他功能,您也可以public

答案 7 :(得分:7)

关于版本控制和API稳定性。在版本1中没有区别 - 但是稍后,如果您决定需要在版本2中将此属性设置为某种类型的错误检查,则无需在任何地方更改API,无需更改代码,财产的定义。

答案 8 :(得分:0)

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

如果你只使用公共属性,那么灵活性就会降低。

在不违反合同的情况下,额外的灵活性对我来说最重要的是使用属性,并且在我真正需要灵活性之前,自动生成是最有意义的。

答案 9 :(得分:0)

我觉得非常有用的一件事以及所有代码和测试原因是,如果它是属性vs字段,则Visual Studio IDE会显示属性的引用但不显示字段。

答案 10 :(得分:0)

做了一些研究后我的观点

  1. 验证。
  2. 允许重写访问器以更改属性的行为。
  3. 调试目的。通过在访问器中设置断点,我们将能够知道属性何时更改以及更改了什么。
  4. 我们只能设置一个字段。例如,public set()和private get()。在公共领域这是不可能的。

它确实为我们提供了更多的可能性和可扩展性。

答案 11 :(得分:0)

您可以对Fields进行操作,但不能对Properties进行操作(或者以前无法使用...一会儿就可以解决),您可以将Fields指定为readonly,而属性不能。因此,Fields为您提供了一种明确的方式来表明您的意图,即仅在对象实例化时(从构造函数内部)设置变量,并且此后不应更改。是的,您可以将Property设置为具有私有setter,但是只说“这不能从类外部更改”,这与“在实例化后不要更改”不同–您仍然可以在课堂上实例化后进行更改。是的,您可以将属性的后备字段设置为只读,但这会使实例化后的尝试将其更改为运行时错误,而不是编译时错误。因此,只读字段做了一些有用的事情,而属性却无法做到。

但是,随着C#9的改变,我们获得了针对属性的有用语法:

public string Height { get; init; }

表示“可以从类外部使用它,但只能在初始化对象时设置它”,因此,Fields的只读优点消失了。

相关问题