C#3.0+中属性和字段的区别

我意识到这似乎是C#中的字段和属性之间有什么区别的重复? 但是我的问题有一点点差别(从我的观点来看):

一旦我知道了

  • 我不会使用我的课程“只能在属性上工作的技巧”
  • 我不会在getter / setter中使用validation码。

有没有什么区别(风格/未来发展的除外),如设置属性的某种types的控制?

是否有任何其他区别:

public string MyString { get; set; } 

 public string myString; 

(我知道,第一个版本需要C#3.0或更高版本,并且编译器确实创build了私有字段。)

封装。

在第二个例子中,你刚刚定义了一个variables,第一个variables周围有一个getter / setter。 所以,如果你决定在晚些时候想要validation这个variables,那将会容易得多。

另外他们在Intellisense中显示出不同的:)

编辑: OP更新更新的问题 – 如果你想忽略其他build议在这里,另一个原因是,它根本不是很好的面向对象devise。 如果你没有足够的理由去做, 总是select一个公共variables/字段的属性。

字段和属性看起来是一样的,但它们不是。 属性是方法,因此属性不支持某些东西,有些属性可能会发生,但从不属于字段。

以下是差异清单:

  • 字段可以用作out/ref参数的input。 属性不能。
  • 一个字段总是会在多次调用时产生相同的结果(如果我们省去了多个线程的问题)。 像DateTime.Now这样的属性并不总是等于它自己。
  • 属性可能会抛出exception – 字段将永远不会这样做。
  • 属性可能有副作用或需要很长时间才能执行。 田地没有任何副作用,并将始终如预期的给定types一样快。
  • 属性支持getter / setter的不同可访问性 – 字段不(但是字段可以readonly
  • 当使用reflection时,属性和字段被视为不同的MemberTypes因此它们的位置不同(例如GetFields vs GetProperties
  • 与现场访问相比,JIT编译器可能会以不同的方式处理财产访问。 然而,它可能会编译到相同的本地代码,但差异的范围在那里。

一对快速,明显的差异

  1. 一个属性可以有访问者关键字。

     public string MyString { get; private set; } 
  2. 属性可以在后代覆盖。

     public virtual string MyString { get; protected set; } 

根本的区别在于,字段是存储指定types的数据的存储器中的位置。 属性表示执行一个或两个单元的代码来检索或设置指定types的值。 这些访问方法的使用在语法上是隐藏的,通过使用一个performance得像一个字段的成员(因为它可以出现在赋值操作的任一侧)。

访问者不仅仅是领域。 其他人已经指出了几个重要的差异,我将再添加一个。

属性参与接口类。 例如:

 interface IPerson { string FirstName { get; set; } string LastName { get; set; } } 

这个接口可以通过几种方式来满足。 例如:

 class Person: IPerson { private string _name; public string FirstName { get { return _name ?? string.Empty; } set { if (value == null) throw new System.ArgumentNullException("value"); _name = value; } } ... } 

在这个实现中,我们保护Person类无法进入无效状态,以及调用者从未分配的属性中取消null。

但我们可以进一步推动devise。 例如,界面可能不会处理setter。 说IPerson接口的消费者IPerson获得财产而不是设置它是完全合理的:

 interface IPerson { string FirstName { get; } string LastName { get; } } 

以前的Person类的实现满足这个接口。 从消费者(消费IPerson )的angular度来看,它允许调用者设置属性的事实是没有意义的。 例如,build设者会考虑具体实施的其他function:

 class PersonBuilder: IPersonBuilder { IPerson BuildPerson(IContext context) { Person person = new Person(); person.FirstName = context.GetFirstName(); person.LastName = context.GetLastName(); return person; } } ... void Consumer(IPersonBuilder builder, IContext context) { IPerson person = builder.BuildPerson(context); Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } 

在这个代码中,消费者并不了解财产制定者 – 这不是他的事。 消费者只需要获得者,并从界面获得获得者,即从合同中获得。

另一个完全有效的IPerson实现将是一个不可变的人员类和一个相应的人工厂:

 class Person: IPerson { public Person(string firstName, string lastName) { if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) throw new System.ArgumentException(); this.FirstName = firstName; this.LastName = lastName; } public string FirstName { get; private set; } public string LastName { get; private set; } } ... class PersonFactory: IPersonFactory { public IPerson CreatePerson(string firstName, string lastName) { return new Person(firstName, lastName); } } ... void Consumer(IPersonFactory factory) { IPerson person = factory.CreatePerson("John", "Doe"); Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } 

在这个代码示例中,消费者再次不知道填充属性。 消费者只处理getter和具体实现(以及后面的业务逻辑,比如testing名称是否为空),留给专门的类 – 构build者和工厂。 所有这些行动都是完全不可能的。

第一个:

 public string MyString {get; set; } 

是财产; 第二个( public string MyString )表示一个字段。

不同之处在于,某些技术(实例的ASP.NET数据绑定)仅适用于属性,而不适用于字段。 XML序列化也是如此:只有属性被序列化,字段不被序列化。

属性和字段在许多情况下可能看起来相似,但它们不是。 对于字段不存在的属性有限制,反之亦然。

正如其他人所提到的。 您可以使属性为只读或只写,通过使访问者为私人。 你不能在一个领域做到这一点。 属性也可以是虚拟的,而字段不能。

将属性看作getXXX()/ setXXX()函数的语法糖。 这是他们如何在幕后实施的。

字段和属性之间还有一个重要的区别。

使用WPF时,只能绑定到公共属性。 绑定到公共领域是行不通的。 即使不执行INotifyPropertyChanged (即使您始终应该),也是如此。

你应该总是使用属性,而不是字段的任何公共fields.This确保你的图书馆有能力实现任何领域的封装,如果将来需要,而不会破坏现有的代码。如果你replace现有库中的属性字段,那么所有的依赖你的库的模块也需要重build。