8.索引器

8.面向对象-封装-索引器


8.1 知识点

知识回顾

class 类名
{
    #region 特征——成员变量
    #endregion

    #region 行为——成员方法
    #endregion

    #region 初始化调用——构造方法
    #endregion

    #region 释放时调用——析构方法
    #endregion

    #region 保护成员变量用——成员属性
    #endregion
}

索引器基本概念

  • 让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写。

索引器基本语法

访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名.....]
{
    // 内部的写法和规则和索引器相同
    get{}
    set{}
}

实例

class Person
{
    private string name;
    private int age;
    private Person[] friends;
  
    //声明索引器
    public Person this[int index]
    {
        //索引器get和set的用法可以说和成员属性几乎一样
        //区别是索引器要传入参数
        get
        {
            //可以写逻辑的 根据需求来处理这里面的内容
            return friends[index];
        }
        set
        {
            friends[index] = value;
        }
    }
}

索引器中可以写逻辑

public Person this[int index]
{
    //索引器get和set的用法可以说和成员属性几乎一样
    //区别是索引器要传入参数

    get
    {
        //可以写逻辑的 根据需求来处理这里面的内容
        //判断朋友数组为不为空或者会不会数组越界
        if (friends == null || friends.Length - 1 < index)
        {
            return null;
        }
        return friends[index];
    }

    set
    {
        //可以写逻辑的 根据需求来处理这里面的内容
        //value代表传入的值
        //判断朋友数组为不为空
        if (friends == null)
        {
            //如果朋友数组为空
            //则开个新房间 把传入的值丢到第一个房间去
            friends = new Person[] { value };
        }
        else if (index > friends.Length - 1)
        {
            //如果传入的索引越界
            //自己定了一个规则 如果索引越界 就默认把最后一个朋友顶掉
            friends[friends.Length - 1] = value;
        }
        else
        {
            //如果朋友数组不为空 且 传入的索引不越界
            //直接赋值即可
            friends[index] = value;
        }
    }
}

索引器可以重载

  • 索引器的重载要点
    • 重载的概念是——函数名相同,参数类型、数量、顺序不同。
    • 可以理解为this就是索引器的函数名。
    • 学了 Object 后,索引器的返回值相当于可以返回任意类型。

实例

  • 参数数量不同的索引器重载

    public int this[int i, int j]
    {
        get
        {
            return array[i, j];
        }
        set
        {
            array[i, j] = value;
        }
    }
    
  • 参数类型不同的索引器重载

    public string this[string str]
    {
        get
        {
            switch (str)
            {
                case "name":
                    return this.name;
                case "age":
                    return age.ToString();
            }
            return "";
        }
    }
    

索引器的使用

主函数内:

Person p = new Person();

p[0] = new Person();
// 使用索引器
// 给 p 的 friends 数组中索引 0 的对象 new 一个 Person 房间
Console.WriteLine(p[0]); // Lesson6_封装_索引器.Person

// p[0, 0] = 10; // 会报错,Person 的二维数组没有初始化

总结

  • 索引器对于我们来说的主要作用

    • 可以让我们以中括号的形式范围自定义类中的元素,规则自己定,访问时和数组一样。
    • 比较适用于在类中有数组变量时使用,可以方便的访问和进行逻辑处理。
  • 固定写法

    • 访问修饰符 返回值 this[参数列表]
    • get 和 set 语句
  • 注意:结构体里面也是支持索引器


8.2 知识点代码

using System;

namespace Lesson6_封装_索引器
{
    #region 知识回顾
    class 类名
    {
        #region 特征——成员变量
        #endregion

        #region 行为——成员方法
        #endregion

        #region 初始化调用——构造方法
        #endregion

        #region 释放时调用——析构方法
        #endregion

        #region 保护成员变量用——成员属性
        #endregion
    }
    #endregion

    #region 知识点一 索引器基本概念
    //基本概念
    //让对象可以像数组一样通过索引访问其中元素,使程序看起来更直观,更容易编写
    #endregion

    #region 知识点二 索引器基本语法

    //基本语法
    //访问修饰符 返回值 this[参数类型 参数名, 参数类型 参数名.....]
    //{
    //      内部的写法和规则和索引器相同
    //      get{}
    //      set{}
    //}

    //实例
    // 人 类
    class Person
    {
        private string name;
        private int age;
        private Person[] friends;

        private int[,] array;

        //声明索引器
        public Person this[int index]
        {
            //索引器get和set的用法可以说和成员属性几乎一样
            //区别是索引器要传入参数

            get
            {
                #region 知识点三 索引器中可以写逻辑
                //可以写逻辑的 根据需求来处理这里面的内容
                //判断朋友数组为不为空或者会不会数组越界
                if (friends == null ||
                    friends.Length - 1 < index)
                {
                    return null;
                }
                #endregion
                return friends[index];
            }

            set
            {
                #region 知识点三 索引器中可以写逻辑
                //可以写逻辑的 根据需求来处理这里面的内容
                //value代表传入的值
                //判断朋友数组为不为空
                if (friends == null)
                {
                    //如果朋友数组为空
                    //则开个新房间 把传入的值丢到第一个房间去
                    friends = new Person[] { value };
                }
                else if (index > friends.Length - 1)
                {
                    //如果传入的索引越界
                    //自己定了一个规则 如果索引越界 就默认把最后一个朋友顶掉
                    friends[friends.Length - 1] = value;
                }
                else
                {
                    //如果朋友数组不为空 且 传入的索引不越界
                    //直接赋值即可
                    friends[index] = value;
                }
                #endregion
            }
        }

        #region 知识点五 索引器可以重载

        //索引器的重载要点
        //重载的概念是——函数名相同 参数类型、数量、顺序不同
        //可以理解为this就是索引器的函数名
        //学了万物之父Object后 索引器的返回值相当于可以返回任意类型

        //实例

        //参数数量不同的索引器重载
        public int this[int i, int j]
        {
            get
            {
                return array[i, j];
            }
            set
            {
                array[i, j] = value;
            }
        }

        //参数类型不同的索引器重载
        public string this[string str]
        {
            get
            {
                switch (str)
                {
                    case "name":
                        return this.name;
                    case "age":
                        return age.ToString();
                }
                return "";
            }
        }

        #endregion
    }
    #endregion


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("索引器");

            #region 知识点五 索引器的使用

            Person p = new Person();

            p[0] = new Person();
            //使用索引器
            //给p的friends数组中索引0的对象new一个Person房间
            Console.WriteLine(p[0]);//Lesson6_封装_索引器.Person

            //p[0, 0] = 10;//会报错 Person的二维数组没有初始化

            #endregion
        }
    }

    //总结

    //索引器对于我们来说的主要作用
    //可以让我们以中括号的形式范围自定义类中的元素 规则自己定 访问时和数组一样
    //比较适用于 在类中有数组变量时使用 可以方便的访问和进行逻辑处理

    //固定写法
    //访问修饰符 返回值 this[参数列表]
    //get和set语句块
    //可以重载

    //注意:结构体里面也是支持索引器
}

8.3 练习题

自定义一个整型数组类,该类中有一个整形数组变量,为它封装增删查改的方法

基本思路

  • 使用list的底层实现原理
  • 初始化时给定一定的房间容量
  • 记录当前使用了几个房间
  • 当房间容量大于等于当前使用了几个房间的值时,直接放
  • 当房间容量小于等于当前使用了几个房间的值时,开更大容量的房间,搬家
  • 避免产生很多垃圾,消耗过多的性能,造成卡顿

class语句块外 namespace语句块内

// class语句块外 namespace语句块内
// 整型数组类
class IntArray
{
    // 基本思路
    // 使用list的底层实现原理
    // 初始化时给定一定的房间容量
    // 记录当前使用了几个房间
    // 当房间容量大于等于当前使用了几个房间的值时 直接放
    // 当房间容量小于等于当前使用了几个房间的值时 开更大容量的房间 搬家
    // 避免产生很多垃圾 消耗过多的性能 造成卡顿

    #region 成员变量

    // 整型数组数组
    private int[] array;
    // 当前房间容量
    private int capacity;
    // 当前使用了几个房间
    private int length;

    #endregion

    #region 成员属性

    public int Length
    {
        get
        {
            return length;
        }
    }

    public int Capacity
    {
        get
        {
            return capacity;
        }
    }

    #endregion

    #region 构造函数

    public IntArray()
    {
        capacity = 4;   // 初始化时,只准备有4个空房间
        length = 0;     // 初始化时,1个房间都没有使用
        array = new int[capacity];  // 开对应数量的房间
    }

    #endregion

    #region 成员方法

    // 增
    public void Add(int value)
    {
        // 如果要增加就涉及扩容
        // 扩容就涉及 "搬家"
        // 但是若每次增加一个元素 就搬一次家的话
        // 会消耗很多性能和产生很多垃圾

        // 当前使用了几个房间的值 小于房间容量
        if (length < capacity)
        {
            // 直接放
            array[length] = value;
            // 使用的房间数+1
            ++length;
        }

        // 当前使用了几个房间的值 大于等于房间容量
        else
        {
            // 准备好开更大容量的新房间
            capacity *= 2;

            // 开新房间
            int[] tempArray = new int[capacity];

            Console.WriteLine("开始搬家,旧房间容量为{0},新房间容量为{1}.", capacity / 2, capacity);

            // 开始搬家 遍历老房间的东西 放进新房间里
            for (int i = 0; i < array.Length; i++)
            {
                tempArray[i] = array[i];
            }

            // 老的房间地址 指向新房间地址
            array = tempArray;

            // 当前房间要存的值 往后面放
            array[length] = value;

            // 使用的房间数+1
            ++length;

            Console.WriteLine("搬家完成,搬家前使用的房间数为{0},搬家后使用的房间数为{1}.", length - 1, length);
        }
    }

    // 删
    // 移除指定值
    public void Remove(int value)
    {
        // 找到传入值在哪个位置
        for (int i = 0; i < length; i++)
        {
            if (array[i] == value)
            {
                RemoveAt(i);
                return;
            }
        }

        // 使用的房间数-1
        Console.WriteLine("没有在数组中找到{0}", value);
    }

    // 移除指定位置
    public void RemoveAt(int index)
    {
        // 判断要移除的索引是否越界
        if (index > length - 1)
        {
            Console.WriteLine("当前数组只有{0},你越界了", length);
            return;
        }

        Console.WriteLine("准备移除索引是{0}的元素,该位置的值是{1}", index, array[index]);

        // 要移除位置的后面所有元素逐个往前搬 覆盖前一个的值
        // 为什么是length - 1不是length
        // 是因为最后一个元素已经往前搬了 值已经copy出来了
        for (int i = index; i < length - 1; i++)
        {
            array[i] = array[i + 1];
        }

        // 搬完后 最后一个空出来的可以回设置默认值 

也可以不处理 
        array[length - 1] = 0;

        // 使用的房间数-1
        --length;

        Console.WriteLine("移除完成,删除前使用的房间数为{0},删除后使用的房间数为{1}.", length + 1, length);
    }

    #endregion

    #region 索引器

    // 查改
    public int this[int index]
    {
        get
        {
            if (index >= length || index < 0)
            {
                Console.WriteLine("越界");
                return 0;
            }
            return array[index];
        }
        set
        {
            if (index >= length || index < 0)
            {
                Console.WriteLine("越界");
            }
            array[index] = value;
        }
    }

    #endregion
}

主函数内

// 主函数内
IntArray myIntArray = new IntArray();

myIntArray.Add(100);
Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:100

myIntArray.Add(200);
myIntArray.Add(300);
myIntArray.Add(400);

Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:4
Console.WriteLine("myIntArray.Capacity:" + myIntArray.Capacity);//myIntArray.Capacity:4
myIntArray.Add(500);
//开始搬家,旧房间容量为4,新房间容量为8.
//搬家完成,搬家前使用的房间数为4,搬家后使用的房间数为5
Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:5
Console.WriteLine("myIntArray.Capacity:" + myIntArray.Capacity);//myIntArray.Capacity:8

Console.WriteLine("myIntArray[1]:" + myIntArray[1]);//myIntArray[1]:200
myIntArray.RemoveAt(10);//当前数组只有5,你越界了
myIntArray.RemoveAt(1);
//准备移除索引是1的元素,该位置的值是200
//移除完成,删除前使用的房间数为5,删除后使用的房间数为4.
Console.WriteLine("myIntArray[1]:" + myIntArray[1]);//myIntArray[1]:300 200已经被移除
myIntArray.Remove(200);//没有在数组中找到200 200已经被移除

Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:100
myIntArray.Remove(100);
//准备移除索引是0的元素,该位置的值是100
//移除完成,删除前使用的房间数为4,删除后使用的房间数为3.
Console.WriteLine("myIntArray[0]:" + myIntArray[0]);//myIntArray[0]:300 100和200已经被移除
Console.WriteLine("myIntArray.Length:" + myIntArray.Length);//myIntArray.Length:3

8.4 练习题代码

using System;

namespace Lesson6_练习题
{
    #region 练习题
    //自定义一个整型数组类,该类中有一个整形数组变量
    //为它封装增删查改的方法

    //class语句块外 namespace语句块内

    // 整型数组 类
    class IntArray
    {
        //基本思路
        //使用list的底层实现原理
        //初始化时给定一定的房间容量
        //记录当前使用了几个房间
        //当前使用了几个房间的值 小于房间容量 时 直接放
        //当前使用了几个房间的值 大于等于房间容量 时 开更大容量的新房间 搬家
        //避免产生很多垃圾 消耗过多的性能 造成卡顿

        #region 成员变量

        //整型数组数组
        private int[] array;
        //当前房间容量
        private int capacity;
        //当前使用了几个房间
        private int length;

        #endregion

        #region 成员属性

        public int Length
        {
            get
            {
                return length;
            }
        }

        public int Capacity
        {
            get
            {
                return capacity;
            }
        }

        #endregion

        #region 构造函数

        public IntArray()
        {
            capacity = 4;//初始化时 只只准备有4个空房间
            length = 0;//初始化时 1个房间都没有使用
            array = new int[capacity];//开对应数量的房间
        }

        #endregion

        #region 成员方法

        //增
        public void Add(int value)
        {
            //如果要增加就涉及扩容
            //扩容就涉及 "搬家"
            //但是若每次增加一个元素 就搬一次家的话
            //会消耗很多性能和产生很多垃圾 

            //当前使用了几个房间的值 小于房间容量 
            if ( length < capacity )
            {
                //直接放
                array[length] = value;
                //使用的房间数+1
                ++length;
            }

            //当前使用了几个房间的值 大于等于房间容量 
            else
            {            
                //准备好开更大容量的新房间
                capacity *= 2;

                //开新房间
                int[] tempArray = new int[capacity];

                Console.WriteLine("开始搬家,旧房间容量为{0},新房间容量为{1}.", capacity / 2, capacity);

                //开始搬家 遍历老房间的东西 放进新房间里
                for (int i = 0; i < array.Length; i++)
                {
                    tempArray[i] = array[i];
                }

                //老的房间地址 指向新房间地址
                array = tempArray;

                //当前房间要存的值 往后面放
                array[length] = value;

                //使用的房间数+1
                ++length;

                Console.WriteLine("搬家完成,搬家前使用的房间数为{0},搬家后使用的房间数为{1}.", length-1, length);
            }
        }

        //删
        //移除指定值
        public void Remove(int value)
        {
            //找到 传入值 在哪个位置
            for (int i = 0; i < length; i++)
            {
                if(array[i] == value)
                {
                    RemoveAt(i);
                    return;
                }
            }

            //使用的房间数-1
            Console.WriteLine("没有在数组中找到{0}", value);
        }
        //移除指定位置
        public void RemoveAt(int index)
        {
            //判断要移除的索引是否越界
            if( index > length - 1 )
            {
                Console.WriteLine("当前数组只有{0},你越界了", length);
                return;
            }

            Console.WriteLine("准备移除索引是{0}的元素,该位置的值是{1}", index, array[index]);

            //要移除位置的后面所有元素逐个往前搬 覆盖前一个的值
            //为什么是length - 1不是length
            //是因为最后一个元素已经往前搬了 值已经copy出来了
            for (int i = index; i < length - 1; i++)
            {
                array[i] = array[i + 1];
            }

            //搬完后 最后一个空出来的可以回设置默认值 也可以不处理 
            array[length-1] = 0;

           //使用的房间数-1
           --length;

            Console.WriteLine("移除完成,删除前使用的房间数为{0},删除后使用的房间数为{1}.", length + 1, length);
        }

        #endregion

        #region 索引器
        //查改
        public int this[int index]
        {
            get
            {
                if( index >= length || index < 0)
                {
                    Console.WriteLine("越界");
                    return 0;
                }
                return array[index];
            }
            set
            {
                if (index >= length || index < 0)
                {
                    Console.WriteLine("越界");
                }
                array[index] = value;
            }
        }

        #endregion
    }

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("索引器练习题");

            //主函数内

            IntArray myInyArray = new IntArray();

            myInyArray.Add(100);
            Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:100

            myInyArray.Add(200);
            myInyArray.Add(300);
            myInyArray.Add(400);

            Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:4
            Console.WriteLine("myInyArray.Capacity:" + myInyArray.Capacity);//myInyArray.Capacity:4
            myInyArray.Add(500);
            //开始搬家,旧房间容量为4,新房间容量为8.
            //搬家完成,搬家前使用的房间数为4,搬家后使用的房间数为5
            Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:5
            Console.WriteLine("myInyArray.Capacity:" + myInyArray.Capacity);//myInyArray.Capacity:8

            Console.WriteLine("myInyArray[1]:" + myInyArray[1]);//myInyArray[1]:200
            myInyArray.RemoveAt(10);//当前数组只有5,你越界了
            myInyArray.RemoveAt(1);
            //准备移除索引是1的元素,该位置的值是200
            //移除完成,删除前使用的房间数为5,删除后使用的房间数为4.
            Console.WriteLine("myInyArray[1]:" + myInyArray[1]);//myInyArray[1]:300 200已经被移除
            myInyArray.Remove(200);//没有在数组中找到200 200已经被移除

            Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:100
            myInyArray.Remove(100);
            //准备移除索引是0的元素,该位置的值是100
            //移除完成,删除前使用的房间数为4,删除后使用的房间数为3.
            Console.WriteLine("myInyArray[0]:" + myInyArray[0]);//myInyArray[0]:300 100和200已经被移除
            Console.WriteLine("myInyArray.Length:" + myInyArray.Length);//myInyArray.Length:3

        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏