属性
书接上回,除了对数据的访问,我们也期望对数据实现一些操作来控制数据,因此我们需要进入一个另一个重量级概念:属性。
定义
属性(property)通常定义为 public,表示类的对外成员。
实现
属性具有可读、可写属性,通过get、set访问器来实现其读写控制,如下:
public class Client
{
private string name;//用户姓名
public string Name
{
get { return name; }
set
{
name = value == null ? string.Empty : value;
}
}
private int age;//用户年龄
public int Age
{
get { return age; }
set
{
if(value>0&&value<150){
age = value;
}
else
{
throw Exception.New("年龄信息不正确");
}
}
}
}
当我们随意输入无效数据,例如 client.age=”10000”时,系统会根据set_Age 中的条件对字段年龄进行控制,从而达到数据的完整性的目的。
查看Client反编译后的情况得知,IL中不存在get、set方法,而是get_Age,set_Age这样的方法。实际编译器的逻辑:如果发现了一个属性,并且查看了该属性是实现了set还是get,就会生成对应的get_属性名、set_属性名方法。因此,我们可以理解为,属性的本质其实在编译时分别将get、set访问器实现为对外方法,从而达到控制属性的目的,而对属性的读写行为伴随的实际是个相应方法的调用,它以一种简单的形式实现了方法。
作用
Get,set对属性的读写控制,是通过get、set的组合来实现的。如果属性只读,就实现get访问器,如果数据可写,就实现set访问器即可。
该做法的好处:
1、避免对数据安全的访问限制,包含内部数据的可靠性。
2、避免类扩展或修改带来的变量连锁反应。
当需求因实际情况发生改变时,减少代码重构,实现最小损失和最大补救。例如,Client.name由原来的简单name标识,修改为firstName和secondName来实现,如果不是属性封装了字段而带来的隐藏内部细节的特点,我们需要拼命替换client.name这样的实现。现在我们只需要这样做:
private string firstName;
private string secondName;
public string Name
{
get { return firstName + secondName; }
}
更改属性定义中的实现细节,就可以适应新需求,这就是封装的强大之处。