• 大话C#之属性


    前言

    俗话说得好:工欲善其事,必先利其器。要想玩转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 = 80;
    //输出“初一三班”
    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 < 0)
                {
                    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(-5);
    //设置学生人数
    sc.SetNum(80);
    //输出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 < 0)
                    throw new ArgumentOutOfRangeException("numBits must be greater than 0");
                m_numBits = numBits;
                m_byteArray = new Byte[(numBits + 7) / 8];
            }
    
            /// <summary>
            /// c#用this来定义索引器,如果要定义多个,只需要重载this[]就可以了
            /// </summary>
            /// <param name="bitPosition"></param>
            /// <returns></returns>
            public Boolean this[Int32 bitPosition]
            {
                get
                {
                    if (bitPosition < 0 && bitPosition >= m_numBits)
                        throw new ArgumentOutOfRangeException("bitPostion must be greater than 0 and less than numBits");
                    return (m_byteArray[bitPosition / 8] & (1 << (bitPosition % 8))) != 0;
                }
                set
                {
                    if (bitPosition < 0 && bitPosition >= m_numBits)
                        throw new ArgumentOutOfRangeException("bitPostion must be greater than 0 and less than numBits");
                    if (value)
                    {
                        m_byteArray[bitPosition / 8] = (Byte)(m_byteArray[bitPosition / 8] | (1 << (bitPosition % 8)));
                    }
                    else
                    {
                        m_byteArray[bitPosition / 8] = (Byte)(m_byteArray[bitPosition / 8] & ~(1 << (bitPosition % 8)));
                    }
                }
            }
        }
    
    //初始化一个含20个位的BitArray数组
    BitArray ba = new BitArray(20);
    
    //调用set访问器为数组的指定位赋值
    for (Int32 i = 0; i < 20; i++)
    {
          ba[i] = (i % 2 != 0);
    }
    
    //调用get访问器查看所有的位状态
    for (Int32 i = 0; i < 20; i++)
    {
          Console.WriteLine("Bit[" + i + "] is " + ba[i] + "");
    }
    Console.ReadLine();

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

  • 相关阅读:
    双日历时间段选择控件—daterangepicker(汉化版)
    vue elementui table表格展开行每次只展开一行
    vue-pdf PDF文件预览
    async await
    vuex发送axios请求
    jq调用浏览器下载文件 window.open()
    禁止页面右键、选择、F12操作
    vue 点击一条消息跳转相应的页面且对应相应的大模块和办理状态
    vue-infinite-scroll 滚动加载下一页
    填写流程当前登录人可以填写除自己可填项外还可看到他前面经办人相关填写的内容,且经办人后面的不可见
  • 原文地址:https://www.cnblogs.com/VersaceAir/p/3452836.html
Copyright © 2020-2023  润新知