属性
许多类型定义的属性可以被重新获得或修改这些属性常常都是用类型字段成员来实现的例如下面是包含有两个字段的类型定义
class Employee {
public String Name;
public Int Age;
}
如果创建这个类型的实例那么很容易用以下代码得到或设置属性
Employee e = new Employee();
eName = Jeffrey Richter; // 设置名字属性
eAge = ; // 设置年龄属性
ConsoleWriteLine(eName); // 显示 Jeffrey Richter
用这种方式使用属性非常普通但以我的观点看上述代码不会向列出的那样被实现面向对象设计和编程的立约之一便是数据抽象它的意思就时类型字段不能用公共字段暴露出来因为它太容易被修改太容易让人写出不恰当地使用这个字段的代码从而破坏对象的状态例如某人很容易编写下面的代码破坏Employee对象
eAge = ; //人的年龄怎么会是呢?
所以说在设计类型时我强烈建议所有字段都是私有的(private)或至少是受保护的(protected)——决不要公共的(public)然后让使用类型的人能Get或Set属性专门为此提供方法打包对字段的访问的方法就叫做存取器(或访问器方法)方法这些方法能随时实现完整性检查并保证对象的状态不被破坏例如我重写了前面定义过的Employee类代码如图一虽然这是一个简单的例子但你能从中明白抽象数据字段的巨大好处你还能从中明白如何轻松实现只读属性或者仅仅通过不去实现某个存取器方法来轻松达到只写属性
显示的数据抽象方法有两个缺点第一因为要实现附加的函数所以要多写一些代码第二类型的使用者现在必须要调用方法而不是仅仅引用单个的字段名
eSetAge(); // Updates the age
eSetAge(); // Throws an exception
我想所有的人都会同意这些缺点与其优点比起来显得微不足道但运行时仍然提供了一种属性机制多少使得第一个缺点容易忍受了并且完全消除了第二个缺点
类使用了属性其功能和上面所示的类相同正如你所看到的属性简化了一些代码但更重要的是允许调用这项下面一样写自己的代码
Age = ; // 更新年龄
eAge = ; // 掷出异常Throws an exception
Get属性存取器的返回值和传递到Set属性存取器参数值类型相同Set属性存取器的返回值是void而Get属性存取器没有入口参数属性可以是静态的虚拟的抽象的内部的私有的保护的或公共的另外属性可以在接口中定义关于这一点将在后面讨论
我还应该指出属性不必于字段关联例如类型SystemIOFileStream定义了一个长度属性它返回流中的字节数当长度属性的Get方法被调用时这个长度不是由字段提供而是调用另一个函数请求底层操作系统返回打开文件流的字节数
当你创建属性时编译器实际上发出专门的get_ProName和/或set_ProName存取器方法(这里ProName是属性名)大多数编译器会理解这些专用方法并允许开发人员存取这些有专门属性语法的方法但是遵守公共语言运行时规范的编译器不需要完全支持属性只要支持专用存取方法调用即可
另外对于完全支持属性的编译器来说在定义和使用属性时使用的语法稍有不同例如带受管扩展的C++需要使用_property关键字
[] [] []