CLR via C# 属性 无参属性

许多类型都定义了能被获取或更改的状态信息。这个状态信息一般作为类型的字段成员实现。

如下代码,我们为这个类型定义两个字段:

创建该类型的实例后,可以使用以下形式的代码轻松获取或者设置它的状态信息:

这种查询和设置对象状态信息的做法十分常见。但是,永远不应该像这样实现。

面向对象设计和编程的重要原则之一就是数据封装,意味着类型的字段永远不应该公开,否则很容易因为不恰当使用字段而破坏对象的状态。

如下代码,我们可以很容易地破坏一个Employee对象:

//--

还有其他原因促使我们封装类型中的数据字段的访问。

1.你可能希望访问字段来执行一些副作用(即side effect;在计算机编程中,如果一个函数或表达式除了生成一个值,还会造成状态的改变,就说它会造成副作用;或者说会执行一个副作用)、缓存某些值或者推迟创建一些内部对象(推迟创建对象是指在对象第一次需要时才真正创建它)。

2.你可能希望以线程安全的方式访问字段。

3.字段可能是一个逻辑字段,它的值不由内存中的字节表示,而是通过某个算法来计算获得。

//--

基于上述原因,强烈建议将所有字段都设为private。要允许用户或类型获取或设置状态信息,就公开一个针对该用途的方法。封装字段访问的方法通常称为访问器(accessor)方法。

访问器方法可选择对数据的合理性进行检查,确保对象的状态永远不被破坏。

虽然这是个简单地例子,但是还可以看出数据字段封装带来的巨大好处。另外可以看出,实现只读属性或只写属性是多么简单,只需选择不实现一个访问器方法即可。另外,将SetXXX方法标记为protected,就可以只允许派生类型修改值。

但是,像这样进行数据封装有两个缺点:

1.因为不得不实现额外的方法,所以必须写更多的代码;

2.类型的用户必须调用方法,而不能直接引用字段名。

//--

编程语言和CLR还是提供了一个称为属性(property)的机制。它缓解了第一个缺点所造成的影响,同时完全消除了第二个缺点。

可将属性想象成智能字段,即背后有额外的字段。CLR支持静态、实例、抽象和虚属性。另外,属性可用任意“可访问性”修饰符来标记,而且可以在接口中定义。

每个属性都有名称和类型(类型不能是void)。属性不能重载,即不能定义名称相同、类型不同的两个属性。定义属性时指定get和set两个方法,但可省略set方法来定义只读属性,或省略get方法来定义只写属性。

经常利用属性的get和set方法操纵类型中定义的私有字段。私有字段通常称为支持字段(backing filed)。但get和set方法并非一定要访问支持字段。

定义属性时,取决于属性的定义,编译器在最后的托管程序集中生成一下两项或三项。

1.代表属性get访问器的方法。仅在属性定义了get访问器方法时生成。

2.代表属性set访问器的方法。仅在属性定义了set访问器方法时生成。

3.托管程序集元数据中的属性定义。这一项必然生成。

编译器在你指定的属性之前自动附加get_或set_前缀类生成方法名。C#内建了对属性的支持。C#编译器发现代码试图获取或设置属性时,实际会生成对上述某个方法的调用。即使编程语言不直接支持属性,也可调用需要的访问器方法来访问属性。效果一样,只是代码看起来没那么优雅。

除了生成访问器方法,针对源代码中定义的每一个属性,编译器还会在托管程序集的元数据中生成一个属性定义项。在这个记录项中包含一些标志(flags)以及属性的类型。另外,它还引用了get和set访问器方法。这些信息唯一的作用就是在“属性”这种抽象概念与它的访问器方法之间建立起一个联系。编译器和其他工具可利用这种元数据信息(使用System.Reflection.PropertyInfo类来获取)。CLR不适用这种元数据信息,在运行时只需要访问器方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值