成员变量:在类中定义的变量
局部变量:在方法中定义的变量
在我们的程序中经常会出现以下代码。
//成员变量
public string Name;
//属性
public class People
{
private string name;
public string Name
{
set { name = value ; }
get { return name; }
}
}
像上面这样的代码到底两者有什么不一样呢?对其他对象来说,这两者都是同样的访问,同样的赋值。一个是变量,一个是属性。
首先基于面向对象的原则来看。面向对象编程的目的是要做到抽象、封装;在类中,变量是对类本身而言的,我们把它叫做域。它可以为 public、 private等;属性是类的外部显示出来的特性。虽然域可以为 public,但这样把域申明为 public 将不利于类的封装,因为外部使用者可以对类进行直接修改。所以我们就可以用到属性,我们只是公开了它们的属性,至于如何对其进行赋值(set)如何进行取值(get)都已经进行了封装(在set和get中我们可以做一些自己的处理),对于类外部是不可见的。
C#中的属性更充分地体现了对象的封装性:不直接操作类的数据内容,而是通过访问器进行访问。借助于 get 和 set 对属性的值进行读写操作和执行语句过程。属性具有多种用法:它们可在允许更改前验证数据;它们可透明地公开某个类上的数据,该类的数据实际上是从其他源(例如数据库)检索到的;当数据被更改时,它们可采取行动,例如引发事件或更改其他字段的值。
【看了属性产生的 IL 代码之后,有读者可能想知道使用属性和使用数据成员在性能上有什么差别。虽然使用属性不会比使用数据成员的代码效率更快,但是它也不见得就会比使用数据成员的代码慢,因为 JIT编译器 会对某些方法调用(包括属性访问器)进行内联处理。如果 JIT编译器 对属性访问器进行了内联处理,那么属性和数据成员的效率将没有任何差别。即使属性访问器没有被内联,实际的效率差别相对于函数调用的成本来讲也是可以忽略不计的。只有在很少的一些情况下,这种差别才值得我们注意。】
由于属性的实质是方法(get或set方法),在 IL 中是没有属性的概念的。所以对于开发过程中常用的赋值和取值操作来说,使用公共变量肯定会比使用属性速度要快,性能上也稍高。
公共字段虽然在速度上快,但它必须开放字段为 public,这样一来对象的调用者便可以直接修改其值,值的内容是否合法,运行中是否会出错,就没有了保障,进而会大大降低类的可重用性;相反,属性类似于方法,它可以对存入的变量的值进行处理,如果觉得该值不合法,可以就地变换或者直接提出警告。这对该类的对象的使用安全有很大好处,在运行过程中,因公共变量值的错误而产生的问题会大大减少。
从上述内容来看,两者各有优缺点,在实际项目开发过程中,我们究竟选择使用哪一种方式呢?
如果满足下面几个条件,那么我们便可以大胆地使用【公共字段】:
1. 允许自由读写;
2. 取值范围只受数据类型约束而无其他任何特定限制;
3. 值的变动不需要引发类中其它任何成员的相应变化;
属性的使用条件则恰好跟变量相反,只要满足下面任何一个条件,就应该使用【属性】:
1. 要求字段只能读或者只能写;
2. 需要限制字段的取值范围;
3. 在改变一个字段的值的时候希望改变对象的其它一些状态;
总结归纳有以下几点区别:
- 属性是对字段的封装。
- 属性可进行数据绑定。
- 属性可进行线程同步。
- 属性可以控制读写,变量不可以。
- 属性可以以接口的形式表现。
- 属性可以是抽象的,变量不可以。
- 属性可以进行赋值操作,变量不可以。
总结:虽然在实际项目的开发过程中,公共字段和属性在合适的条件下都可以使用,但是我们应该尽可能的使用属性(property),而不是数据成员(field);把所有的字段都设置为私有字段,如果要暴露它们,则把它们封装成属性,这也是微软推荐的方式。