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

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

public class Book
{
    private string _title;

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

好吧,我有一个忏悔,我不能忍受写所有这些(真的,不是必须写它,而是必须看它),所以我擅自使用了公共字段。

然后出现了c# 3.0,我看到他们添加了自动属性:

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

哪个更整洁,我很感激,但说真的,这和仅仅创建一个公共字段有什么不同呢?

public class Book
{
    public string Title;
}

当前回答

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

其他回答

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

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

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

今天让它成为一个自动属性没什么,3个月后你意识到你想让它惰性加载,并在getter中放一个空检查。如果您使用了一个字段,最好的情况下这是一个重新编译的更改,最坏的情况下这是不可能的,这取决于谁和什么依赖于您的程序集。

对我来说,不使用公共字段的绝对原因是缺乏智能感知,显示引用:

字段不可用。

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

属性与公共变量

反射在变量和属性上的工作方式不同,因此如果依赖于反射,则更容易使用所有属性。 你不能对变量进行数据绑定。 将变量更改为属性是破坏性的更改。例如: TryGetTitle (book.Title);//需要一个变量