C# 3.0自动属性 - 有用还是无用?

157

注意:这篇文章是我刚开始学习C#时发的。以我2014年的知识,我可以真诚地说auto-properties是C#语言中最好的东西之一。

我习惯使用一个私有和一个公共字段来创建我的C#属性:

private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

现在,使用.NET 3.0,我们可以使用自动属性:

public string Title { get; set; }

除了为每个字段节省五行代码,是否有任何理由使用这些自动属性?我的个人不满是这些属性将一些东西隐藏起来了,而且我不是黑魔法的忠实粉丝。

实际上,即使在调试器中,隐藏的私有字段也不会显示出来,这没关系,因为get/set函数什么都不做。但是当我想要实际实现一些getter/setter逻辑时,我仍然必须使用私有/公有对。

我看到的好处是,我可以节省大量代码(1行对6行),而不失去以后更改getter/setter逻辑的能力,但是我已经可以通过仅声明一个公共字段“Public string Title”而无需{ get; set; }块来实现这一点,从而节省更多代码。

那么,我错过了什么?为什么有人实际上想要使用自动属性呢?


90
我个人的不满是这些属性在向我隐藏东西,而我不喜欢黑魔法。什么?你肯定知道编译器一直在向你隐藏大量信息,对吧?除非你正在写汇编(或更准确地说,是代码的实际1和0),否则你所写的每一样东西都在向你隐藏信息。 - Charles Boyung
17个回答

121
我们在Stack Overflow中经常使用它们。
您可能也会对属性 vs 公共变量的讨论感兴趣。在我看来,这实际上是对此的反应,而且对于那个目的而言,它非常好。

64

是的,它确实只是保存代码。当你有大量的代码时,使用它会更容易阅读。编写速度更快,维护更容易。保存代码总是一个不错的目标。

您可以设置不同的范围:

public string PropertyName { get; private set; }

属性只能在类内更改。但这并不是真正的不可变性,因为您仍然可以通过反射访问私有 setter。

从C#6开始,您还可以创建真正的readonly属性——即不可变属性,在构造函数外部无法更改:

public string PropertyName { get; }

public MyClass() { this.PropertyName = "whatever"; }

在编译时将变为:

readonly string pName;
public string PropertyName { get { return this.pName; } }

public MyClass() { this.pName = "whatever"; }
在具有许多成员的不可变类中,这可以节省很多冗余代码。

2
@wal - 有什么需要调试的吗?从那个角度来看,你基本上是在处理成员变量。 - Keith
6
你可以像访问成员变量一样在它们上面设置断点,只是你不能进入它们。但是,你为什么要这样做呢?自动属性实际上所做的事情既微不足道又是自动生成的,如果你有 bug,那么它们极不可能出现在这个地方。 - Keith
3
基思,也许我们需要到室外谈谈。 :) - wal
1
但是,假设您有许多对myObj.Title的setter调用...您想查看从“text”更改为null的值的位置,即条件断点。您如何实现?您甚至无法在setter上设置断点。 - wal
只是想了解一下 readonly 和 "private set",很酷,谢谢。 - CallMeLaNN
显示剩余2条评论

47

使用字段而非属性的三个主要缺点是:

  1. 无法将数据绑定到字段,但可以将其绑定到属性
  2. 如果一开始使用字段,稍后想要将其更改为属性就不太容易了
  3. 有些属性可以添加到属性中,但不能添加到字段中

7
如果您一开始使用了一个字段,后来想要将其更改为属性可能会很困难(或不容易)。抱歉,为什么? - Homam
6
主要是,任何在你的字段上使用反射的消费者代码都会出现问题,因为它们必须从使用FieldInfo切换到使用PropertyInfo。 - Isabelle Wedin
9
将一个字段改为属性会破坏二进制兼容性,需要重新编译使用该字段的所有消费者。 - Odrade
1
除了重新编译和反射问题之外,使用Visual Studio封装字段非常容易:Ctrl-R + E将允许您将字段转换为具有适当getter / setter的属性(或右键单击字段,重构,封装字段)。 - JoeBrockhaus
@Hommam 字段是 lvalues(它们是变量),而属性不是。当字段变成属性时,可能会编译失败的代码。 - Mark

30

来自C++创始人Bjarne Stroustrup的说法:

我尤其不喜欢有很多get和set函数的类。这通常是它本不应该是一个类的迹象。它只是一个数据结构。如果它确实是一个数据结构,那就把它做成一个数据结构吧。

你知道吗?他说得对。你有多少次只是在用get和set简单地包装一些私有字段,而没有在get/set中实际执行任何操作,只是因为这是“面向对象”的做法。这是微软解决这个问题的方案;它们基本上是可以绑定的公共字段。


2
我真的认为这个应该有更多的分数。太多人把自动属性看作是编写可怕封装(或根本没有封装)的类的绿灯,而这些类仅仅是一个炫耀的公共字段。当然,这更多是关于人们如何使用工具而不是工具本身的问题,但我认为在讨论属性时提到这一点很重要。 - sara

30

我个人喜欢自动属性。节省代码行数有何不可?如果你想在getter或setter中执行操作,之后将它们转换为普通属性也没有问题。

正如你所说,你可以使用字段,如果以后要向它们添加逻辑,则可以将它们转换为属性。但是这可能会导致任何反射的使用问题(可能还有其他地方?)

此外,属性允许您为getter和setter设置不同的访问级别,而字段无法做到这一点。

我想这就像var关键字一样,是个人喜好的问题。


18

似乎没有人提到的一件事情是,自动属性对于不可变对象(通常是不可变结构体)不太有用。因为你真正应该做的是:

private readonly string title;
public string Title
{
    get { return this.title; }
}

(在构造函数中通过传递的参数初始化字段,然后只读地读取字段。)

因此,这比简单的get/private set自动属性有优势。


3
public string Title { get; private set; } 不会产生任何不同的结果吗?当然,您可以从类内部更改它,但如果这样做,就会出现其他问题... :p - Svish
@Svish,这并不完全相同,因为只有在构造或声明时才能设置只读字段,而私有setter可以在同一类中的非构造方法中设置。 - Zaid Masud
2
@Svish - 按照这个论点,在C#中使用readonly关键字也不应该,因为它的使用意味着我们正在隐藏这些“不同的问题”。 - Zaid Masud
2
我只是指从外部 API 的角度来看,这并没有太大的区别。因此,如果需要,可以使用自动属性。当然,最好的方法是像这样做:public string Title { get; private readonly set; } - Svish
我有时会将.NET类型分为两组:可以在.NET中编写的类型(HttpRequestButton)和只能在.NET下面编写并具有.NET“接口”以便我们可以使用它们的类型(objectThread)。有人可能认为BinaryFormatter属于后一种类型。但事实并非如此。任何人都可以用C#重写它。很明显,只读字段必须随时可更新,因为反序列化图形否则需要魔法,因为在一般情况下,构造函数参数和只读字段之间没有确定的关系:FormatterServices.PopulateObjectMembers - Eduard Dumitru
显示剩余7条评论

12

我总是创建属性而不是公共字段,因为您可以在接口定义中使用属性,而无法在接口定义中使用公共字段。


8

自动属性在C#中就像其他任何东西一样神秘。但是,如果你从编译成IL的角度来考虑它,而不是将其扩展为普通的C#属性,那么它就比许多其他语言结构更容易理解了。


5

我认为任何直观且能减少代码行数的结构都是一个大优点。

这种特性就是让像Ruby这样的语言变得强大的原因(还有动态特性,也有助于减少冗余代码)。

Ruby一直拥有这个特性:

attr_accessor :my_property
attr_reader :my_getter
attr_writer :my_setter

5
我经常使用自动属性。在 C#3 之前,我不想费力去输入更多的字符,就直接使用公共变量了。
唯一我错过的是这样做的能力:
public string Name = "DefaultName";

你必须使用属性将默认值传递给构造函数。这有点繁琐 :-(


5
通过 C# 6 中的自动属性初始化器,您不久就能够做到这一点:public string Name { get; set; } = "DefaultName";。来源:http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx - Carlos Muñoz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接