前言

俗话说得好:工欲善其事,必先利其器。要想玩转OOP设计出一个优秀的类型,属性是必不可少的,那么我们今天就来说说c#中关于属性的二三事。

属性(property)分为无参属性(parameterless property)和有参数性(parameterful property),在c#中有参属性又被称作索引器(indexer),以后看见索引器就别再感到陌生啦,本质上就一属性嘛。废话不多说,下面赶紧说说无参属性和索引器。

无参属性

话说在很久很久以前,那时候都还没有属性,但是设计类型时总会需要定义可以被获取或者更改的状态信息,当时人们是怎么干的呢?先来看看下面这段代码:

public sealed class SchoolClass {
/// <summary>
/// 班级名称
/// </summary>
public String Name;
/// <summary>
/// 学生人数
/// </summary>
public Int32 StudentNum;
}
//创建一个SchoolClass类型
SchoolClass sc = new SchoolClass();
//设置班级名称
sc.Name = "初一三班";
//设置学生人数
sc.StudentNum = ;
//输出“初一三班”
Console.WriteLine(sc.Name);

这段代码中首先定义了一个类型,类型中定义了两个字段,创建类型的实例以后,轻松地设置了类型中的状态信息。不可否认,这种做法是可以达到读取和设置对象状态信息的目的,但是又引入了一个新的问题,类型使用者可以很轻松地将StudentNum设置为-10(稍微一想就明白这不符合正常的逻辑,怎么人数会比0小呢?)。也许有人会说了,这简单啊把StudentNum的可访问级别设为private就完了呗,这当然起到了一定作用,但是在类型外引用该类型怎么访问StudentNum呢?既然讨论不出结果,就让我们看看前人是怎么解决的,请看下面这段代码:

public sealed class SchoolClass
{
/// <summary>
/// 班级名称,现在字段是私有的
/// </summary>
private String Name;
/// <summary>
/// 学生人数,现在字段是私有的
/// </summary>
private Int32 StudentNum;
/// <summary>
/// 修改Name值的访问
/// </summary>
/// <param name="value"></param>
public void SetName(String value)
{
Name = value;
}
/// <summary>
/// 获取Name值的方法
/// </summary>
/// <returns></returns>
public String GetName()
{
return Name;
}
/// <summary>
/// 设置StudentNum的方法
/// </summary>
/// <param name="value"></param>
public void SetNum(Int32 value)
{
if (value < )
{
throw new ArgumentOutOfRangeException("value", value.ToString(), "人数必须大于0!");
}
StudentNum = value;
}
/// <summary>
/// 获取StudentNum的方法
/// </summary>
/// <returns></returns>
public Int32 GetNum()
{
return StudentNum;
}
}
//创建一个SchoolClass类型
SchoolClass sc = new SchoolClass();
//设置班级名称
sc.SetName("初一三班");
//获取班级名称,显示“初一三班”
Console.WriteLine(sc.GetName());
//设置学生人数,会抛出ArgumentOutOfRangeException异常
sc.SetNum(-);
//设置学生人数
sc.SetNum();
//输出80
Console.WriteLine(sc.GetNum().ToString());

在修改后的代码中,我们将SchoolClass类型中定义的Name和StudentNum字段都设为了private,并且分别为它们定义了两个方法:一个读取值一个修改值。这样我们就可以在SetXXX()方法里面加入逻辑从而保护类型不被破坏掉。这样做是达到了目的,但是我们必须分别为每一个字段定义GetXXX()和SetXXX()方法,c#为我们提供了无参属性来方便地达到上述目的,请看下面这段代码:

public sealed class SchoolClass
{
private String m_Name;
private Int32 m_StudentNum;
public String Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
}
}
public Int32 StudentNum
{
get
{
return m_StudentNum;
}
set
{
//关键字value总是代表新值,即调用属性的代码为属性赋的值
if (value < 0)
{
throw new ArgumentOutOfRangeException("value", value.ToString(), "人数必须大于0!");
}
m_StudentNum = value;
}
}
} SchoolClass sc = new SchoolClass();
sc.Name = "初一三班";
Console.WriteLine(sc.Name);
sc.StudentNum = 80;
Console.WriteLine(sc.StudentNum);

在这段代码中我们重新定义了SchoolClass类型,并且为该类型定义了两个属性,然后通过访问属性来达到了为类型定义私有字段,然后为私有字段定义SetXXX()和GetXXX()方法同样的目的。我们可以看到属性都具有get和set访问器(get和set叫做访问器),分别用来控制属性的读操作和写操作,当然也可以选择性地实现get或者set访问器,只实现get访问器的属性称为只读属性,只实现set访问器的称为只写属性(属性只能读不能写当然毫无意义,当然也通不过c#编译器的编译)。说到这里我想对无参属性应该有一个大致的了解了吧,那下面我们来说一下有参属性,有了无参属性的基础理解有参属性就容易多了,让我们来一起看一下:

有参属性

无参属性的get访问器不接受参数,为了弥补这个缺憾,c#开发组提供了有参属性,有参属性的get访问器可以接受一个或多个参数,set访问器可以接受两个或多个参数,我们来看看下面这段代码:

    /// <summary>
/// 定义一个位数组类型
/// </summary>
public sealed class BitArray
{
/// <summary>
/// 位数组长度
/// </summary>
private Int32 m_numBits;
/// <summary>
/// 位数组
/// </summary>
private Byte[] m_byteArray; /// <summary>
/// 构造函数,初始化位数组
/// </summary>
/// <param name="numBits"></param>
public BitArray(Int32 numBits)
{
if (numBits < )
throw new ArgumentOutOfRangeException("numBits must be greater than 0");
m_numBits = numBits;
m_byteArray = new Byte[(numBits + ) / ];
} /// <summary>
/// c#用this来定义索引器,如果要定义多个,只需要重载this[]就可以了
/// </summary>
/// <param name="bitPosition"></param>
/// <returns></returns>
public Boolean this[Int32 bitPosition]
{
get
{
if (bitPosition < && bitPosition >= m_numBits)
throw new ArgumentOutOfRangeException("bitPostion must be greater than 0 and less than numBits");
return (m_byteArray[bitPosition / ] & ( << (bitPosition % ))) != ;
}
set
{
if (bitPosition < && bitPosition >= m_numBits)
throw new ArgumentOutOfRangeException("bitPostion must be greater than 0 and less than numBits");
if (value)
{
m_byteArray[bitPosition / ] = (Byte)(m_byteArray[bitPosition / ] | ( << (bitPosition % )));
}
else
{
m_byteArray[bitPosition / ] = (Byte)(m_byteArray[bitPosition / ] & ~( << (bitPosition % )));
}
}
}
} //初始化一个含20个位的BitArray数组
BitArray ba = new BitArray(); //调用set访问器为数组的指定位赋值
for (Int32 i = ; i < ; i++)
{
ba[i] = (i % != );
} //调用get访问器查看所有的位状态
for (Int32 i = ; i < ; i++)
{
Console.WriteLine("Bit[" + i + "] is " + ba[i] + "");
}
Console.ReadLine();

怎么样?索引器很简单也很好用吧,下篇博客我们来说说c#中的事件,敬请期待哟!哈哈。

大话C#之属性的更多相关文章

  1. jqu

    1 /*2 * 说明:3 * 本源代码的中文注释乃Auscarlin呕心沥血所作.旨在促进jQuery的传播以及向广大jQuery爱好者提供一个进阶4 *的途径,以让各位更加深入地了解jQuery,学 ...

  2. linkin大话面向对象--属性详解

    成员变量和局部变量 成员变量: 1.在一个类中,任何方法之外定义的变量:     2.从面向对象的思想来说我们又把实例变量看成一个类的属性.     3.实例变量在没有符初值时系统会自动帮我们做初始化 ...

  3. 大话listview之设置item监听器无效大坑之一:item设了属性clickable

    今天一个listview设置item监听器居然没有作用: 看了半天,怀疑是item设置了这个属性, 于是删了,果然就可以了. 大坑 ...

  4. Atitti 大话存储读后感 attilax总结

    Atitti 大话存储读后感 attilax总结 1.1. 大话存储中心思想(主要讲了磁盘文件等存储)1 1.2. 最耐久的存储,莫过于石头了,要想几千万年的存储信息,使用石头是最好的方式了1 1.3 ...

  5. 大熊君大话NodeJS之------Net模块

    一,开篇分析 从今天开始,我们来深入具体的模块学习,这篇文章是这个系列(大熊君大话NodeJS)文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中, 对NodeJS也有一个基本的认识,没事 ...

  6. 《火球——UML大战需求分析》(第1章 大话UML)——1.2 结构型的UML(Structure Diagram)

    说明: <火球——UML大战需求分析>是我撰写的一本关于需求分析及UML方面的书,我将会在CSDN上为大家分享前面几章的内容,总字数在几万以上,图片有数十张.欢迎你按文章的序号顺序阅读,谢 ...

  7. SQL SERVER大话存储结构(3)_数据行的行结构

            一行数据是如何来存储的呢?     变长列与定长列,NULL与NOT NULL,实际是如何整理存放到 8k的数据页上呢?     对表格进行增减列,修改长度,添加默认值等DDL SQL ...

  8. SQL SERVER大话存储结构(6)_数据库数据文件

            数据库文件有两大类:数据文件跟日志文件,每一个数据库至少各有一个数据文件或者日志文件,数据文件用来存储数据,日志文件用来存储数据库的事务修改情况,可用于恢复数据库使用.     这里分 ...

  9. java 之 原型模式(大话设计模式)

    原型模式,在笔者理解看来就是克隆,当我们在创建第一个对象时,已经给对象赋值完毕,此时我们需要一个当前对象的副本,如果没有原型模式,我们会再次创建一个对象,然后后二次赋值,保证两个对象完全一致, 这样我 ...

随机推荐

  1. 使用了Theme但是没有效果问题

    最近在开发过程中使用了theme移植Preference并使用了一些android样式,但是在自定义的Theme修改了相关参数后却无法实现 可能有些朋友还不知道怎么用.这里也做个简要的使用方式说明. ...

  2. 正整数转换成N进制的数组

    给定一个正整数,按照N进制转换成数组元素存储 //给定一个整数,把它转换成按照N进制存储的数组 #include <stdio.h> #include <stdlib.h> # ...

  3. UCOS2_STM32F1移植详细过程(四)

    Ⅰ.概述 上一篇文章是讲述uC/OS-II Ports下面os_cpu_a.asm.os_cpu_c.c和os_cpu.h文件底层端口代码的移植(修改)和说明,接着上一篇文章来讲述关于UCOS移植应用 ...

  4. 菜鸟学习Hibernate——多对多关系映射

    Hibernate中的关系映射,最常见的关系映射之一就是多对多关系映射例如用户与角色的关系,一个用户对应多个角色,一个角色对应多个用户.如图: Hibernate中如何来映射这两个的关系呢? 下面就为 ...

  5. kettle过滤、生成随机数、改变开始复制数量

    下面是一个用Kettle实现数据过滤.生成随机数.改变开始复制数量的连贯示意图. 首先,我们将控件一一建立,通过hop建立连接 下面对每一个控件进行设置 1.生成随机数控件(随机取一个数字与字符串) ...

  6. Python数据类型-----数字&字符串

    Python数字类型 int类型表示的范围:-2147483648至2147483648之间,超出这个范围的数字即视为long(长整形) 在Python中不需要事先声明数据类型,它是根据具体的赋值来进 ...

  7. Android--Fragment的懒加载

    我们都知道,fragment放在viewPager里面,viewpager会帮我们预先加载一个,但是当我们要看fragment里面的内容时,我们也许只会去看第一个,不会去看第二个,如果这时候不去实现f ...

  8. hdu 5281 Senior's Gun

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5281 Senior's Gun Description Xuejiejie is a beautifu ...

  9. OpenStack的bridge_sto off的解释

    北京_张华(28620211) 2014/1/27 星期一 11:10:57传统的网络是通过STP协议来避免交换机在二层形成环路,但是对于虚拟交换机,因为有东西向的流量,故将bridge_stp设成o ...

  10. iOS学习之基础控件

    一.UILabel      1.UILabel(标签):是显示文本的空间.在App中UILabel是出现频率最高的控件.      2.UILabel是UIView的子类,作为子类一般是为了扩充父类 ...