我们经常被告知,应该通过为类字段创建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;
}

当前回答

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

字段不可用。

其他回答

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

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

对我来说,使用属性时最重要的是在不破坏契约的情况下获得额外的灵活性,在我真正需要这种灵活性之前,自动生成是最有意义的。

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

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

因为属性是作为非常薄的方法实现的,所以可以在其值的读写上设置断点。这让它们在田野上占据了很大的优势。

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

Trivial properties like these make me sad. They are the worst kind of cargo culting and the hatred for public fields in C# needs to stop. The biggest argument against public fields is future-proofing: If you later decide you need to add extra logic to the getter and setter, then you will have to do a huge refactor in any other code that uses the field. This is certainly true in other languages like C++ and Java where the semantics for calling a getter and setter method are very different from those for setting and getting a field. However, in C#, the semantics for accessing a property are exactly the same as those for accessing a field, so 99% of your code should be completely unaffected by this.

我所见过的一个将字段更改为属性的例子实际上是源代码级别的破坏性更改,如下所示:

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

对此,我要问,为什么TF要传递其他类的字段作为引用?依赖于它不是一个属性似乎是这里真正的编码失败。假设您可以直接写入另一个类中的数据,而您对此一无所知,这是一种糟糕的实践。制作你自己的局部变量和集书。标题就是这样的。任何做这种事情的代码都应该被打破。

我还看到了其他反对的观点:

Changing a field to a property breaks binary compatibility and requires any code that uses it to be recompiled: This is a concern iff you are writing code for distribution as a closed-source library. In that case, yes, make sure none of your user-facing classes have public fields and use trivial properties as needed. If however you are like 99% of C# developers and writing code purely for internal consumption within your project, then why is recompilation a big concern? Just about any other change you make is going to require recompilation too, and so what if it does? Last I checked, it is no longer 1995, we have fast computers with fast compilers and incremental linkers, even larger recompilations shouldn't need more than a few minutes, and it has been quite some time since I have been able to use "my code's compiling" as an excuse for swordfighting through the office. You can't databind against a variable: Great, when you need to do that, make it into a property. Properties have features that make them better for debugging like reflection and setting breakpoints: Great, one you need to use one of those things, make it into a property. When you're done debugging and ready to release, if you don't still need those functionalities, change it back into a field. Properties allow you to override behavior in derived classes: Great, if you are making a base class where you think such a scenario is likely, then make the appropriate members into properties. If you're not sure, leave it as a field and you can change it later. Yes, that will probably require some recompilation, but again, so what?

所以总的来说,是的,对于一些不重要的属性有一些合法的用途,但是除非你是在为公共发布制作一个闭源库,否则在需要的时候,字段很容易转换成属性,而对公共字段的非理性恐惧只是一些面向对象的教条,我们应该很好地摆脱它。

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

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