自1.0版本以来,c#对属性进行了一系列的增强,让其表达能力不断提高。你可以对setter和geter指定不同的访问权限。同时隐式属性也极大降低了声明属性的工作量,不会比声明数据成员麻烦多少。如果你还在类型中声明公有成员,那么快停下来吧,下面我们来对比一下两者的优缺点:
1,属性可以创建出类似于数据访问,但实际上却是方法调用的接口,所以它可以享受到方法调用的所有好处。
2,客户代码访问属性的时候,就像是在访问公有字段,不过其底层使用方法实现,其中还可以自由定义属性访问器的行为。
3,.Net Framework中的数据绑定类仅支持属性,而不支持公有数据成员,对所有的数据绑定类库均是如此,包括WPF,Windows Forms和Silverlight。数据绑定机制将使用反射来找到类型中的特定属性:
textBoxCity.DataBindings.Add("Text",address,"City");这段代码将textBoxCity控件的Text属性绑定到address对象的City属性上。
4,在日后有新的需求或者行为时,属性更易于修改。例如客户要求名称不能为空,若你使用了属性来封装Name,那么只需要修改一处即可:
public class Customer { private string name; public string Name { get { return name; } set { if (string.IsNullOrEmpty(value)) { throw new ArgumentException("名称不能为空","Name"); } name = value; } } }
但是如果使用了公有数据成员,你就需要查找每一处设置名称的代码并逐一修复。想想这会花费你多少时间。
5,由于属性是使用方法来现实的,所以添加多线程支持也非常简单,很容易在即有的属性的get和set访问器中做出如下修改:
public class Customer { private object syncHandle = new object(); private string name; public string Name { get { lock (syncHandle) return name; } set { if (string.IsNullOrEmpty(value)) { throw new ArgumentException("名称不能为空", "Name"); } lock (syncHandle) name = value; } } }
6,属性可以拥有方法的所有语言特性,例如属性可以为虚的(virtual)
public virtual string Name { get; set; }
7,属性的访问器将作为两个独立的方法编译到你的类型中。在c#中,你可以get和set访问器设置不同的访问权限。这样你可以精妙的控制属性暴露出来的数据成员的可见性:
public virtual string Name { get; protected set; }
8,属性的功能很强大,是个不错的改进。但是你是不是还在考虑先用公有数据成员来实现,然后再改成属性呢?这个看似不错的策略,其实却行不通。来看下面的代码:
public class Customer { public string Name; } string name=customerOne.Name; customerOne.Name="Jim";
看似简单直观,你可以认为若是日后将Name改成属性,那么代码可以无需任何修改。但是这个答案并不是完全正确。属性仅仅是在访问时类似于数据成员,但是属性的访问和数据的访问将会生成不同的MSIL语言。所以当你想更新单一程序集变得非常困难。
9,性能比较
若是你查看生成的IL,那么你或许会比较一下两者的性能,属性当然不会比数据成员访问快,不过也不会比它差多少,只要不在属性访问器中执行长时间的计算或者进行跨应用程序的调用(例如执行数据库操作)。
无论何时需要在类型的公有或者保护接口中暴露数据,都应该使用属性,所有的数据成员都应该是私有的,没有任何例外。
对于将变量封装成一个属性所需的额外输入工作其实不会占用太多时间,但是对于今后的维护却带来很大的方便。