C#3.0自动属性-是否有用?[关闭]


155

注意:这是我刚开始使用C#时发布的。凭借2014年的知识,我可以真正地说出,自动属性是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逻辑时,无论如何我都必须使用私有/公共对。

我看到的好处是,我节省了很多代码(一行vs六行),而不会在以后失去更改getter / setter逻辑的能力,但是话又说回来,我已经可以通过简单地声明一个公共字段“ Public string Title”来做到这一点。 {获取;组; }块,从而节省更多代码。

那么,我在这里想念什么?为什么有人实际上要使用自动属性?


86
“我个人的抱怨是,这些财产对我来说是隐藏的东西,我不是黑魔法的忠实拥护者。” ??您知道编译器一直在向您隐藏大量信息,对吧?除非您正在编写汇编程序(或更准确地说,是代码的实际1和0),否则您编写的所有内容都会对您隐藏。
Charles Boyung 2010年

Answers:



62

是的,它只是保存代码。拥有大量负载时,阅读起来容易得多。它们编写起来更快,维护起来也更容易。保存代码始终是一个好目标。

您可以设置不同的范围:

public string PropertyName { get; private set; }

这样该属性只能在类内部进行更改。这并不是真正不变的,因为您仍然可以通过反射访问私有设置器。

从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-有什么要调试的?从这个角度来看,您基本上是在处理成员变量。
基思2010年

6
@wal-您可以在它们上设置一个断点,就像可以访问成员变量一样,就不能进入它们。但是为什么要呢?自动属性的实际作用既是琐碎的又是自动生成的,如果您发现的bug只是其中之一,那么它们极不可能出现。
基思2010年

3
我们可能需要在基思之外进行。:)
wal

1
但是好吧,假设您有许多对myObj.Title的setter调用...您想查看该值从“ text”更改为null(即条件断点)的位置。您如何实现的?您甚至无法在设置器上设置断点
沃尔玛

45

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

  1. 您无法将数据绑定到字段,而可以绑定到属性
  2. 如果您开始使用字段,则以后不能(轻松地)将其更改为属性
  3. 您可以将某些属性添加到无法添加到字段的属性中

7
“如果您开始使用字段,则以后不能(轻松地)将它们更改为属性”,对不起,为什么?
霍姆

6
@Homam主要是,任何在字段上使用反射的使用者代码都将中断,因为它们必须从使用FieldInfo切换到PropertyInfo。
WCWedin 2010年

8
@Homam此外,将字段更改为属性会破坏二进制兼容性,这要求该字段的所有使用者重新编译。
奥德拉德(Odrade)2011年

1
除了重新编译和反射问题之外,使用Visual Studio封装字段非常容易:Ctrl-R + E允许您将字段转换为具有适当的getter / setter的属性。(或右键单击该字段,进行重构,封装字段)。
JoeBrockhaus

@Hommam字段是左值(它们是变量),而属性不是。当它是一个字段时,可能已经编译的东西可能不是它。
标记

29

我个人喜欢自动属性。保存代码行怎么了?如果您想在getter或setter中做一些事情,以后再将它们转换为普通属性是没有问题的。

如您所说,您可以使用字段,如果以后想向它们添加逻辑,则可以将它们转换为属性。但这可能会在使用反射时(以及可能在其他地方使用)带来问题。

此外,这些属性还允许您为getter和setter设置不同的访问级别,而这是您无法使用字段进行的。

我想它与var关键字相同。个人喜好问题。


29

来自C ++的创建者Bjarne Stroustrup:

我特别不喜欢带有很多get和set函数的类。这通常表明它本来不应该是一门课。这只是一个数据结构。如果确实是数据结构,请使其成为数据结构。

你知道吗?他是对的。您只是多频繁地将私有字段包装在一个get和set中,而实际上没有在get / set中做任何事情,仅仅是因为这是“面向对象”的事情。这是Microsoft解决该问题的方法。它们基本上是可以绑定的公共字段。


2
我真的认为这应该有更多要点。太多的人认为自动属性是编写可怕封装(或根本没有封装)类的开绿灯,这些类仅仅是一个美化的公共领域。当然,这与人们如何使用该工具有关,而不是与工具本身有关,这是一个更大的问题,但是我认为在讨论一般属性时必须提到这一点很重要。
萨拉(Sara)2015年

18

似乎没有人提到的一件事是,不幸的是,自动属性对不可变对象(通常是不可变结构)没有用。为此,您确实应该这样做:

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

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

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


如果您具有结构,则更改其上的任何属性都会产生一个新的结构。仅当您需要内部不可变的引用类型时,这才是一个问题-我看不出您为什么需要一个引用类型的原因。
基思

@基思:您的第一句话似乎不正确。
多梅尼克2009年

3
会不会public string Title { get; private set; }导致完全相同的结果?您当然可以从班级内部进行更改,但是,如果这样做,您还会遇到其他问题...:p
Svish

2
@Svish-通过该参数,切勿使用C#中的readonly关键字,因为它的使用将意味着我们隐藏了这些“不同的问题”
Zaid Masud

2
我只是说,从外部API的角度来看,不会有太大的不同。因此,如果需要,可以使用自动属性。最好的事情当然是如果您可以做类似的事情public string Title { get; private readonly set; }
Svish

12

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


8

自动属性与C#中的其他任何东西一样都是黑魔法。一旦从编译为IL而不是首先将其扩展为普通C#属性的角度考虑它,它就比许多其他语言构造少了很多黑魔法。


5

我一直都在使用自动属性。在C#3之前,我不会为所有键入感到烦恼,而只是使用了公共变量。

我唯一想念的是能够做到这一点:

public string Name = "DefaultName";

您必须将默认值转移到带有属性的构造函数中。乏味的:-(


4
从C#6自动初始化属性,你会很快就可以做到这一点:public string Name { get; set; } = "DefaultName"; blogs.msdn.com/b/csharpfaq/archive/2014/11/20/...
卡洛斯·穆尼奥斯

5

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

这些功能使Ruby之类的语言如此强大(具有动态功能,这也有助于减少多余的代码)。

Ruby一直这样:

attr_accessor :my_property
attr_reader :my_getter
attr_writer :my_setter

2

我对他们的唯一问题是他们走得不够远。同一版本的编译器增加了自动属性,增加了部分方法。为什么他们没有把两者放在一起,这超出了我。一个简单的“部分On <PropertyName> Changed”将使这些事情真的非常有用。


您可以将多个部分方法放在另一个方法中。为他们创建某种自动模式会令人困惑。
马修·怀特

2

这很简单,很短,如果您想在属性的主体内部创建一个真正的实现,它不会破坏您类型的外部接口。

就如此容易。


1

据我了解,这里需要注意的一件事是,这只是 C#3.0端的语法糖,这意味着编译器生成的IL是相同的。我同意避免使用黑魔法,但是对于同一件事,所有相同,更少的行通常是一件好事。


1

我认为,应该始终使用自动属性而不是公共字段。也就是说,这是一个折衷方案:

内部字段开始,使用要用于属性的命名约定。当您第一次

  • 需要从其组件外部访问该字段,或者
  • 需要将逻辑附加到getter / setter

做这个:

  1. 重命名字段
  2. 设为私人
  3. 添加公共财产

您的客户代码无需更改。

但是,总有一天,您的系统会不断增长,并且您会将其分解为单独的程序集和多个解决方案。发生这种情况时,任何公开的字段都会再次困扰您,因为正如Jeff所提到的,将公共字段更改为公共属性是API的重大更改


0

我使用CodeRush,它比自动属性要快。

去做这个:

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

总共需要八次击键。


5
如果按住CTRL和V键,则可以/ really快速/粘贴很多东西,但这并不能使它“更好”。这如何回答原始问题?
JBRWilkinson'2

0

加上代码片段,同名的自动属性总共将是七个击键;)


0

@Domenic:我不明白..你不能用自动属性吗?:

public string Title { get; }

要么

public string Title { get; private set; }

这是您所指的吗?


您可以(后者;前者将无法编译),但随后字段在您的对象内不是不变的。
多米尼克

请注意,标记为只读时,只有结构是不可变的,类是无法分配的。
古凡特

0

我对自动属性的最大抱怨是,它们旨在节省时间,但是我经常发现我后来不得不将它们扩展为完整的属性。

VS2008缺少的是爆炸自动属性重构。

我们具有封装字段重构的事实使我可以更快地使用公共字段。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.