我对C#很新,我觉得属性很棒。事实上,如此精彩,我看不到使用字段的任何真正优势。即使对于私人领域,性能提供的灵活性和模块性似乎最多可以避免严重的麻烦,最糟糕的是根本没有效果。
我可以在字段中看到的唯一优势是您可以内联初始化它们。但是大多数时候,你想在构造函数中初始化它们。如果您不使用内联初始化,是否有任何理由不使用属性?
编辑:有些人提出需要使用字段备份属性(显式或自动)。让我们澄清一下我的问题:除了备份属性之外,有没有理由使用字段?即,SomeType someField;
是否优先SomeType SomeProperty { get; set; }
?
编辑2:DanM,Skurmedel和Seth都提供了非常有用的答案。我已经接受了DanM,因为它是最完整的,但如果有人将他们的回答总结为一个答案,我很乐意接受它。
答案 0 :(得分:25)
通常,属性需要一个支持字段,除非它们是简单的getter / setter“自动属性”。
所以,如果你只是在......
public string Name { get; set; } // automatic property
......你不需要一个领域,我同意,没有理由拥有一个领域。
但是,如果你正在......
public string Name
{
get { return _name; }
set
{
if (value = _name) return;
_name = value;
OnPropertyChange("Name");
}
}
...您需要_name
支持字段。
对于不需要任何特殊get / set逻辑的私有变量,它实际上是一个判断调用,无论是私有自动属性还是只是一个字段。我通常做一个字段,然后,如果我需要protected
或public
,我会将其更改为自动属性。
<强>更新强>
正如Yassir所指出的那样,如果你使用自动属性,那么幕后仍然会有潜伏的场地,这不是你实际需要输出的东西。因此,底线是:属性不存储数据,它们提供对数据的访问。字段是实际保存数据的内容。所以,即使你看不到它们,也需要它们。
更新2
关于你修改过的问题......
是否有任何时候SomeType someField;优于
SomeType SomeProperty { get; set; }
?
...有一件事让我想到:如果你有一个私人领域,并且(根据私人领域的惯例)你称之为_name
,它会向你和任何阅读你的代码的人发出信号直接使用私人数据。另一方面,如果您将所有内容都设为属性,并且(根据属性约定)调用您的私有属性Name
,现在您不能只查看变量并告诉它是私有数据。因此,仅使用属性会删除一些信息。我没有尝试过使用所有属性来衡量这是否是至关重要的信息,但肯定会丢失一些东西。
另一件事,更轻微的是,public string Name { get; set; }
需要比private string _name
更多的打字(并且有点麻烦)。
答案 1 :(得分:12)
属性是一件很棒的事情 - 但是存在与属性访问相关的开销。不一定是问题,但需要注意的事项。
避免过度使用财产管理员和信箱
大多数人都没有意识到,在开销方面,属性getter和setter与方法类似;它主要是区分它们的语法。除了字段访问之外不包含任何指令的非虚拟属性getter或setter将由编译器内联,但在许多其他情况下,这是不可能的。你应该仔细考虑你对财产的使用;从类内部直接访问字段(如果可能),并且从不盲目地重复调用属性而不将值存储在变量中。总而言之,这并不意味着你应该使用公共领域!
答案 2 :(得分:11)
使用ref / out args时尝试使用属性:
someObject.SomeMethod(ref otherObject.SomeProperty);
它不会编译。
答案 3 :(得分:10)
如果你想要一些readonly
,你几乎必须使用一个字段,因为无法告诉自动属性生成一个只读字段。
我经常这样做。
受挫的例子:
class Rectangle
{
private readonly int _width;
private readonly int _height;
public Rectangle(int width, int height)
{
_width = width;
_height = height;
}
public int Width { get { return _width; } }
public int Height { get { return _height; } }
}
这意味着Rectangle内部的任何内容都不能改变构造后的宽度或高度。如果有人试图编译器会抱怨。
如果我使用私有设置器的自动属性,则编译器不会保护我自己。
我看到的另一个原因是,如果不需要公开数据(保持private
),为什么要将其作为属性?
答案 4 :(得分:5)
虽然我同意我认为David Basarab的声明中的“意图”:“没有理由公开曝光字段,”我想补充一点略有不同:
我将以上大卫的引用修改为:“没有理由公开暴露字段......在课堂外...除非通过有意识地选择封装属性中的字段来严格控制访问权限
属性不仅仅是字段“贴在”C#上的“单板”语法:它们是一个基本的语言功能,其设计理由很充分,包括:
控制暴露的内容而不暴露在类外(封装,数据隐藏)
允许在访问或设置属性时执行某些操作:最好在属性“获取和”设置中表示的操作,而不是“提升”到外部定义的方法。
< / LI>设计界面不能定义'字段:但可以定义属性。
良好的OO设计意味着对“状态”做出有意识的选择:
局部变量字段:方法的私有状态和瞬态:局部变量通常仅在方法体的范围内有效,或者甚至与“缩短生命周期”一样有效在'for循环'之类的范围内。当然,您也可以将方法中的参数变量视为“本地”。
类实例字段:什么状态是类的私有状态,并且对于每个类的实例都有独立的存在,但很可能需要在类的多个位置使用。
静态实例字段:什么状态只是类的属性,与类的实例数无关。
故意并有意识地将“外部”暴露在课堂之外:关键的想法是,班级和班级所暴露的数据的“消费者”之间至少存在一个间接层次。当然,“曝光”的“另一面”是隐藏(封装,隔离)实现代码的意图。
一个。通过公共财产:这里所有其他答案都涵盖了这方面的所有方面
湾通过索引器
℃。通过方法
d。公共静态变量通常位于实用程序类中,通常是静态类。
建议您查看:MSDN on 'Fields ... MSDN on Properties ... MSDN on Indexers
答案 5 :(得分:4)
我不明白你为什么要使用私人autoproperties。
有什么好处private int Count {get; set;}
在
private int count
答案 6 :(得分:3)
没有 公开公开字段的理由。
如果您公开公开某个字段,则无法更改信息来源,从内联定义到配置文件而不进行重构。\
您可以使用字段隐藏内部数据。我很少赞成这一点,当我做一些公开隐藏并在房产中使用它时,我只使用字段。 (即我没有使用自动属性生成)
答案 7 :(得分:3)
字段是您可以存储州的唯一地方。属性实际上只是一对具有特殊语法的方法,允许它们根据它们的使用方式映射到get或set方法:如果属性修改或访问状态,该状态仍然必须存储在字段中
您并不总是看到这些字段。使用C#3自动属性,编译器将为您创建该字段。但它仍然存在。此外,自动属性有一些显着的限制(例如,没有INotifyPropertyChanged支持,在setter中没有业务逻辑),这意味着它们通常是不合适的,并且您无论如何都需要创建显式字段和手动定义的属性。
根据David's answer,如果您正在谈论API,那么您就是对的:您几乎从不想让内部状态(字段)成为API的一部分。
答案 8 :(得分:3)
字段的语法写入比使用属性要快得多,因此当使用字段(对类私有)时,为什么不使用它并保存额外的输入呢?如果自动实现的属性具有简洁的简洁语法,并且您不得不做额外的工作来创建一个普通的旧字段,那么人们可能只是开始使用属性。此外,它现在是C#的惯例。这就是人们的思考方式,也是他们期望在代码中看到的东西。如果你做了与正常情况不同的事情,你会让所有人感到困惑。
但你可以问为什么字段的语法不会创建一个自动实现的属性而不是一个字段,所以你可以充分利用这两个世界 - 各地的属性和简洁的语法。
我们仍然需要有明确的字段,这是一个非常简单的原因:
C#1.0没有我们现在拥有的所有这些优秀功能,所以字段是生活中的事实 - 如果没有它们你就无法生存。许多代码依赖于字段和属性是明显不同的东西。在不破坏大量代码的情况下,它现在无法更改。
我还怀疑存在性能影响,但也许这可以通过抖动来解决。
所以我们永远坚持使用字段,因为它们在那里并且它们采用了最好的语法,所以在安全的情况下使用它们是有意义的。
答案 9 :(得分:2)
字段和属性不可互换。我猜你所说的是通过私有财产访问私人领域。我这样做是有意义的,但在大多数情况下,没有必要。在大多数情况下,JIT优化器将通过私有属性内联访问私有字段。无论如何,将私有字段包装在私有财产中不会被视为重大变更,因为私有成员不是您的界面的一部分。
就个人而言,我永远不会公开任何受保护/公共实例字段。虽然只要字段类型本身是不可变的,但通常使用只读修饰符公开公共静态字段是可以接受的。这通常出现在SomeStruct.Empty静态字段中。
答案 10 :(得分:2)
正如其他人所指出的那样,无论如何你都需要一个私人支持字段。
在属性上使用字段也有速度优势。在99.99%的情况下,这无关紧要。但有些人可能会这样做。
答案 11 :(得分:0)
答案 12 :(得分:0)
@Seth有几个好的(部分)答案(字段表现更好,因此在私人环境中你可能会在有意义的时候使用它),@ Skurmedel(字段可以只读),@ Jenk (字段可用于ref / out)。但是我想补充一点:
您可以使用简化的初始化语法来设置字段的值,但不能使用属性。即:
private int x = 7;
VS
private int x { get; set; }
// This must go in the constructor, sometimes forcing you to create
// a constructor that has no other purpose.
x = 7;