[CLR via C#]10. 属性
一、无参属性
对于字段,强烈建议将所有的字段都设为private。如果允许用户或类型获取或设置状态信息,就公开一个针对该用途的方法。封装了字段访问的方法通常称为访问器(accessor)方法。访问器方法可选择对数据的合理性进行检查,确保对象的状态永远不被破坏。如下代码:
- private sealed class Employee
- {
- private String m_Name;
- private Int32 m_Age;
- public String GetName(){
- return m_Name;
- }
- public void SetName(String value){
- m_Name = value;
- }
- public Int32 GetAge(){
- return m_Age;
- }
- public void SetAge(Int32 value){
- if (value <= )
- throw new ArgumentOutOfRangeException("value", "must be >0");
- m_Age = value;
- }
- }
想这样的数据封装有两个缺点。第一:不得不实现额外的方法;第二、用户必须调用方法。
- private sealed class Employee {
- private String m_Name;
- private Int32 m_Age;
- public String Name {
- get { return (m_Name); }
- set { m_Name = value; } // 关键字'value' 总是代表新值
- }
- public Int32 Age {
- get { return (m_Age); }
- set {
- if (value <= ) // 关键字'value' 总是代表新值
- throw new ArgumentOutOfRangeException("value", "must be >0");
- m_Age = value;
- }
- }
- }
于是就可以这样调用:
- Employee emp = new Employee();
- emp.Name = "Jeffrey Richter";
- emp.Age = ;
- Console.WriteLine("Employee info: Name = {0}, Age = {1}", emp.Name, emp.Age);
可将属性想象成智能字段,即背后有额外逻辑的字段。CLR支持静态、实例、抽象和虚属性。属性可以使用任意可访问性修饰符修饰。
- private sealed class Employee {
- //这是一个自动实现属性
- public String Name {get;set;}
- }
2.合理定义属性
属性和字段的比较:
- Employee e = new Employee[()] { Name = "Jeff", Age = }
- string s = new Employee() {Name = "Jeff", Age = }.ToString().ToUpper();
- //定义一个类型,后再它的一个实例,并初始化它的属性
- var o1 = new { Name = "Jeff", Year = };
- Console.WriteLine("Name={0}, Year={1}", o1.Name, o1.Year);
第一行代码创建了一个匿名类型,没有在new 关键字后制定类型名称,所以编译器会为我自动创建一个类型名称,而且不会告诉我这个名称是什么(这正是匿名类型一词的由来),但编译器是知道的。虽然我不知道变量o1声明的是什么类型,但可以利用C#的"隐式推断类型局部变量"功能(var)。
编译器支持用另外两种语法声明匿名类型中的属性,它根据变量推断出属性名和类型:
- String Name = "Grant";
- DateTime dt = DateTime.Now;
- // 有两个属性的一个匿名类型
- // 1. String Name 属性设为"Grant"
- // 2. Int32 Year 属性设为dt中的年份
- var o2 = new { Name, dt.Year };
在这个例子中,编译器判断第一个属性名为Name。由于Name是一个局部变量的名称,所以编译器将属性类型设为与局部变量相同的类型:String。对于第二个属性,编译器使用字段/属性的名称:Year。Year是DateTime类的一个Int32属性,所以匿名类型中的Year属性也是一个Int32。
- //这是最简单的
- public class Tuple<T1> {
- private T1 m_item1;
- public Tuple(T1 item1) { m_Item1 = item1;}
- public item1 { get { retuen m_Item1; } }
- }
和匿名类型相似,一旦创建好了一个Tuple,他就不可变了(所有属性都只读)。Tuple类还提供了CompareTo,Equals,GetHashCode和ToString方法,另外还提供了一个Size属性。除此之外,所有Tuple类型都实现了IstruralEquatable,IstructuralComparable和IComparable接口,所以可以比较两个Tuple对象。
- internal sealed class BitArray {
- // 容纳了二进制位的私有字节数组
- private Byte[] m_byteArray;
- private Int32 m_numBits;
- // 下面的构造器用于分配字节数组,并将所有位设为 0
- public BitArray(Int32 numBits) {
- // 先验证实参
- if (numBits <= )
- throw new ArgumentOutOfRangeException("numBits must be > 0");
- // 保留位的个数
- m_numBits = numBits;
- // 为位数组分配字节
- m_byteArray = new Byte[(m_numBits + ) / ];
- }
- // 下面是索引器(有参属性)
- public Boolean this[Int32 bitPos] {
- // 下面是索引器的get访问器方法
- get {
- // 先验证实参
- if ((bitPos < ) || (bitPos >= m_numBits))
- throw new ArgumentOutOfRangeException("bitPos", "bitPos must be between 0 and " + m_numBits);
- // 返回指定索引处的位的状态
- return ((m_byteArray[bitPos / ] & ( << (bitPos % ))) != );
- }
- // 下面是索引器的set访问器方法
- set {
- if ((bitPos < ) || (bitPos >= m_numBits))
- throw new ArgumentOutOfRangeException("bitPos", "bitPos must be between 0 and " + m_numBits);
- if (value) {
- // 将指定索引处的位设为true
- m_byteArray[bitPos / ] = (Byte)
- (m_byteArray[bitPos / ] | ( << (bitPos % )));
- } else {
- // 将指定索引处的位设为false
- m_byteArray[bitPos / ] = (Byte)
- (m_byteArray[bitPos / ] & ~( << (bitPos % )));
- }
- }
- }
- }
BitArray类的调用也非常简单:
- private static void BitArrayTest() {
- // 分配含有14个位的bitArray数组
- BitArray ba = new BitArray();
- // 调用set访问器方法,将编号为偶数的所有为设为true
- for (Int32 x = ; x < ; x++) {
- ba[x] = (x % == );
- }
- // 调用get访问器方法显示所有为的状态
- for (Int32 x = ; x < ; x++) {
- Console.WriteLine("Bit " + x + " is " + (ba[x] ? "On" : "Off"));
- }
- }
三、调用属性访问器方法时的性能
四、属性访问器的可访问性
我们有时希望为get访问器方法指定一种可访问性,为set访问器方法指定另一种可访问性。如下:
- public class SomeType {
- private String m_name;
- public String Name {
- get { return m_name;}
- protected set { m_name = value;}
- }
- }
定义一个属性时,如果两个访问器方法需要具有不同的可访问性,C#语法要求必须为属性本身指定限制最不大的那一种可访问性。然后,在两个访问器中,只能选择一个来应用限制较大的那一种可访问性。如前面例子中,属性本身声明为public,set访问器方法声明为protected(限制比public大)。
五、泛型属性访问器方法
[CLR via C#]10. 属性的更多相关文章
- CLR类型设计之属性
在之前的随笔中,我们探讨了参数,字段,方法,我们在开始属性之前回顾一下,之前的探讨实际上串联起来就是OOP编程的思想,在接下来的文章中,我们还会讨论接口(就是行为),举个例子:我们如果要做一个学生档案 ...
- 【CLR in c#】属性
1.无参属性 1.为什么有字段还需要属性呢? 因为字段很容易写出不恰当的代码,破坏对象的状态,比如Age=-1.人的年纪不可能为负数.使用属性后你可以缓存某些值或者推迟创建一些内部对象,你可以以线程安 ...
- 【C#进阶系列】10 属性
属性分为无参属性和有参属性(即索引器). 属性相对于字段的优点不仅仅是为了封装,还可以在读写的时候做一些额外操作,缓存某些值或者推迟创建一些内部对象,也适用于以线程安全的方式访问字段. 话说最基本的属 ...
- 重温CLR(七 ) 属性和事件
无参属性 许多类型都定义了能被获取或更高的状态信息.这种状态信息一般作为类型的字段成员实现.例如一下类型包含两个字段: public sealed class Employee{ public str ...
- CLR via C#深解笔记四 - 方法、参数、属性
实例构造器和类(引用类型) 构造器(constructor)是允许将类型的实例初始化为良好状态的一种特殊方法.构造器方法在“方法定义元数据表”中始终叫.ctor. 创建一个引用类型的实例时: #1, ...
- CLR VIA C# 学习笔记
第19章 可空类型 1)使用Nullable<T>可将int32的值类型设置为Null,CLR会在Null时默认赋值为0; 如:Nullable<T> x=null; //使用 ...
- 【CLR VIA C#】读书笔记
工作几年了才看,记录下笔记备忘. 章节 笔记 1.CLR的执行模型 公共语言运行时(Common Language Runtime,CLR) 源代码-->编译器检查语法和分析源代码-->托 ...
- CLR总览
Contents 第1章CLR的执行模型... 4 1.1将源代码编译成托管代码模块... 4 1.2 将托管模块合并成程序集... 6 1.3加载公共语言运行时... 7 1.4执行程序集的代码.. ...
- CLR 完全介绍
From: http://msdn.microsoft.com/zh-cn/magazine/cc164193.aspx http://msdn.microsoft.com/en-us/magazin ...
随机推荐
- PHP - 如何使用XDEBUG来远程调试?
开发的时候我都是使用XDebug在本地调试,但是最近加入一些项目中去,环境太复杂了,要在本地搭建一个开发环境真的太麻烦了,那么我们怎么使用xdebug来远程调试呢? 我这里使用虚拟机搭建了一个模拟环境 ...
- [GraphQL] Use GraphQL's Object Type for Basic Types
We can create the most basic components of our GraphQL Schema using GraphQL's Object Types. These ty ...
- State状态设计模式
1.状态模式:改变对象的行为 一个用来改变类的(状态的)对象. 2:问题:当你自己实现 State 模式的时候就会碰到很多细节的问题,你必须根据自己的需要选择合适的实现方法, 比如用到的状态(Stat ...
- Android手机的 storage
老外的一段解释 -------------------------------------------------------------------------------------------- ...
- 几种常用远程通信技术(RPC,Webservice,RMI,JMS)的区别
原文链接:http://blog.csdn.net/shan9liang/article/details/8995023 RPC(Remote Procedure Call Protocol) RPC ...
- AD10长方形通孔焊盘的画法
1.点击工具栏中[放置焊盘]按钮 2.按键盘Tab键弹出[焊盘]对话框 3.设置[空洞信息]相关尺寸(根据自己所需实际设置) 这里左边的单选按钮选择“槽”,通孔尺寸输入20mil,长度为80mil,旋 ...
- 解决Visual Studio 2010新建工程时出现『1>LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt』错误
VS2010在经历一些更新后,建立Win32 Console Project时会出"error LNK1123" 错误. 解决方案为: 第一步:将:项目|项目属性|配置属性|清 ...
- ODAC (V9.5.15) 学习笔记(二十一)数据复制
用TVirtualTable在内存中缓存TOraQuery中的数据,主要应用场景是参照其他数据,需要将TOraQuery中的数据复制到TVirtualTable,由于没有类似于TClientDataS ...
- windows7 中开启无线热点
我用的是移动的 CMCC-EDU 上网,但是这个只能在一个设备上登陆,那么问题就来了,当我电脑需要用网,手机也想要用网(不用 2/3/4G)该怎么办? 电脑操作系统:windows7 接下来是开启 w ...
- SVN分支与合并
分支的基本概念就正如它的名字,开发的一条线独立于另一条线,如果回顾历史,可以发现两条线分享共同的历史,一个分支总是从一个备份开始的,从那里开始,发展自己独有的历史(如下图所示) ⑴创建分支 假设目前我 ...