C#学习笔记11:索引器、运算符重载、ToString()方法

-呈阶梯状分布- 31 次阅读 1418 字 发布于 2026-08-14 最后更新于 2026-08-14 C#学习笔记


索引器

我们对数组进行索引操作时,通常通过 数组名[下标] 进行读写,如下面代码:

int[] arr = new int[] {1, 2, 3};
Console.WriteLine(arr[0]);  // 读取
arr[1] = 4;  // 写入

我们希望在自己的类中也能通过 [下标] 的方式对对象进行操作,就需要用到索引器了。现在,创建一个名为Test的类。

using System;

namespace Csharp
{
    class Test
    {
        
    }
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
}

然后为他加上索引器。

using System;

namespace Csharp
{
    class Test
    {
        public int this[int index]
        {
            get
            {
                return 0;
            }
            set
            {
                
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
}

可以看出,索引器在结构上与属性类似,都有一个get和一个set,分别对应读写这两大功能。
索引器的定义结构为"public (get的返回值) this[下标类型 index] { get{} set{} }"。
其中,get返回值不得为void(即无返回值),index只是下标的形式参数名,可以修改。
索引器的get返回值必须与value类型相同。
你也能从下标需要指定类型看出,下标可以不只是int类型的整数。
set中赋入的值同属性一样也是以名为value的形参传入。

此时,我们就可以创建一个字符串数组类型,下标就是内容。
通过构造函数和参数数组传入数组的元素。
使用get时,返回数组中存在该内容的个数的字符串类型,使用set时,将从左到右的第一个目标内容进行修改。
这是get返回值和value类型必须相同的无奈之举......
下面是通过索引器的实现:

using System;

namespace Csharp
{
    class StringArray
    {
        private string[] stringArray;
        public string this[string index]
        {
            get
            {
                int times = 0;
                foreach(string temp in stringArray)
                {
                    if (temp == index)
                    {
                        times++;
                    }
                }
                return ""+times;
            }
            set
            {
                for (int i = 0; i < stringArray.Length; i++)
                {
                    if (stringArray[i] == index)
                    {
                        stringArray[i] = value;
                    }
                }
            }
        }
        public StringArray(params string[] tarr)
        {
            stringArray = tarr;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
}

这里不再在Main函数中对索引器测试,你可以自行复制代码后尝试,以下是测试用例:
var t = new StringArray("a", "b", "c", "b"); // 实例化
Console.WriteLine(t["b"]); // 读取 返回2(字符串类型的2)
t["b"] = "s"; // 写入 最左边的"b"被修改为"s"

运算符重载

我们希望对两个int类型的数进行比较,可以使用==、>=、<=等等运算符,对于==运算符,其比较的是两个int类型的值是否相同。
然而,对于两个用我们的类创建的对象,其默认的==比较符逻辑是比较两个对象的内存地址是否相同,就像我们前面接触到的object.ReferenceEquals()。
如果我们希望前面的StringArray中,两个对象即使内存地址不同,其内部存的字符串数组相同就判定相等,就需要对==运算符进行重载,改变其逻辑。
运算符重载定义如下:

public static 返回值 operator运算符(左值类型 n1, 右值类型 n2)
{
    代码块...
}

对于==运算符,返回值一般为bool类型(即是否相等),n1是一个形式参数,名称可以修改,n2同理。
对于a==b,a会传入n1,b会传入n2,同样,n1和n2类型也要确定,且至少有一个参数类型与本类一致。
可以对单个运算符的重载进行多个参数重载,就像函数重载一样。
我们为StringArray加上==判定,对了,如果有重载==,也要重载!=,可以直接调用==并用!取反,代码如下(修改了字段stringArray为public以便读取比较):

using System;

namespace Csharp
{
    class StringArray
    {
        public string[] stringArray;
        public string this[string index]
        {
            get
            {
                int times = 0;
                foreach(string temp in stringArray)
                {
                    if (temp == index)
                    {
                        times++;
                    }
                }
                return ""+times;
            }
            set
            {
                for (int i = 0; i < stringArray.Length; i++)
                {
                    if (stringArray[i] == index)
                    {
                        stringArray[i] = value;
                    }
                }
            }
        }
        public static bool operator==(StringArray n1, StringArray n2)
        {
            if (n1.stringArray == n2.stringArray) return true;
            return false;
        }
        public static bool operator!=(StringArray n1, StringArray n2)
        {
            return !(n1 == n2);
        }
        public StringArray(params string[] tarr)
        {
            stringArray = tarr;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            
        }
    }
}

如此一来,我们就能按照我们所希望的逻辑比较两个用我们写的类创建的对象了。

ToString()方法

我们尝试一下创建一个StringArray对象,并用Console.WriteLine()输出他:

using System;

namespace Csharp
{
    class StringArray
    {
        public string[] stringArray;
        public string this[string index]
        {
            get
            {
                int times = 0;
                foreach(string temp in stringArray)
                {
                    if (temp == index)
                    {
                        times++;
                    }
                }
                return ""+times;
            }
            set
            {
                for (int i = 0; i < stringArray.Length; i++)
                {
                    if (stringArray[i] == index)
                    {
                        stringArray[i] = value;
                    }
                }
            }
        }
        public static bool operator==(StringArray n1, StringArray n2)
        {
            if (n1.stringArray == n2.stringArray) return true;
            return false;
        }
        public static bool operator!=(StringArray n1, StringArray n2)
        {
            return !(n1 == n2);
        }
        public StringArray(params string[] tarr)
        {
            stringArray = tarr;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            StringArray t = new StringArray();
            Console.WriteLine(t);
        }
    }
}

输出结果如下:

Csharp.StringArray

可以看到,输出的结果有些奇怪,但不难看出是 命名空间(namespace).类名(class) ,也就是对象所在的类。
如果我们希望改变这种情况,让其输出整个数组呢?
我们可以对ToString()方法进行重载,在对象被当作字符串使用时,就会调用这个方法进行返回:

using System;

namespace Csharp
{
    class StringArray
    {
        public string[] stringArray;
        public string this[string index]
        {
            get
            {
                int times = 0;
                foreach(string temp in stringArray)
                {
                    if (temp == index)
                    {
                        times++;
                    }
                }
                return ""+times;
            }
            set
            {
                for (int i = 0; i < stringArray.Length; i++)
                {
                    if (stringArray[i] == index)
                    {
                        stringArray[i] = value;
                    }
                }
            }
        }
        public static bool operator==(StringArray n1, StringArray n2)
        {
            if (n1.stringArray == n2.stringArray) return true;
            return false;
        }
        public static bool operator!=(StringArray n1, StringArray n2)
        {
            return !(n1 == n2);
        }
        public override string ToString()
        {
            string result = "[";
            foreach (string temp in stringArray)
            {
                result += temp;
                result += ", ";
            }
            result = result.TrimEnd(' ').TrimEnd(',');  // 去除尾部字符
            result += "]";
            return result;
        }
        public StringArray(params string[] tarr)
        {
            stringArray = tarr;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            StringArray t = new StringArray("Ladder", "Step", "PolarLand");
            Console.WriteLine(t);
        }
    }
}

输出结果如下:


[Ladder, Step, PolarLand]

可见,我们成功改写了输出逻辑,让对象查看变得更为直观便捷。

OK,下一篇泛型、列表!