0

0

C#的索引器是什么?如何使用?

煙雲

煙雲

发布时间:2025-09-06 08:51:03

|

1004人浏览过

|

来源于php中文网

原创

C#索引器是一种带参数的特殊属性,允许通过索引像访问数组或字典一样操作对象成员,适用于封装集合或映射数据,提升代码直观性与可读性。

c#的索引器是什么?如何使用?

C#的索引器,简单来说,就是一种允许你像访问数组一样,通过索引(比如整数或字符串)来访问对象成员的特殊语法结构。它让你的类表现得像一个集合,但实际上,你可以自定义这个“索引”背后的逻辑,这在处理集合类型数据时特别方便,让代码更直观。

解决方案

索引器(Indexer)在C#中,本质上是一个带有参数的属性(Property)。它允许你为类的实例定义一个默认的索引行为,使得你可以使用方括号

[]
语法来访问对象内部的数据,就像操作数组或列表那样。这对于那些封装了内部集合或需要通过某种键值来访问数据的类来说,是非常有用的。

实现一个索引器,你需要使用

this
关键字,并指定一个或多个参数类型作为索引。它通常包含
get
set
访问器,分别用于读取和写入数据,其工作方式和属性的访问器非常相似。

例如,我们有一个表示书籍集合的类,希望通过书名来获取书的详细信息:

using System;
using System.Collections.Generic;

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int Year { get; set; }

    public Book(string title, string author, int year)
    {
        Title = title;
        Author = author;
        Year = year;
    }

    public override string ToString()
    {
        return $"{Title} by {Author} ({Year})";
    }
}

public class Library
{
    private List _books;

    public Library()
    {
        _books = new List();
    }

    public void AddBook(Book book)
    {
        _books.Add(book);
    }

    // 定义一个索引器,通过书名(string)来访问Book对象
    public Book this[string title]
    {
        get
        {
            foreach (var book in _books)
            {
                if (book.Title.Equals(title, StringComparison.OrdinalIgnoreCase))
                {
                    return book;
                }
            }
            return null; // 如果找不到,返回null
        }
        set
        {
            // 在这里可以实现更新或添加逻辑
            // 简单示例:如果存在,则更新;否则添加
            bool found = false;
            for (int i = 0; i < _books.Count; i++)
            {
                if (_books[i].Title.Equals(title, StringComparison.OrdinalIgnoreCase))
                {
                    _books[i] = value; // 更新
                    found = true;
                    break;
                }
            }
            if (!found)
            {
                _books.Add(value); // 添加
            }
        }
    }

    // 也可以定义一个通过索引(int)来访问的索引器
    public Book this[int index]
    {
        get
        {
            if (index >= 0 && index < _books.Count)
            {
                return _books[index];
            }
            throw new IndexOutOfRangeException("索引超出范围。");
        }
        set
        {
            if (index >= 0 && index < _books.Count)
            {
                _books[index] = value;
            }
            else
            {
                throw new IndexOutOfRangeException("索引超出范围,无法设置。");
            }
        }
    }
}

// 使用示例
public class Program
{
    public static void Main(string[] args)
    {
        Library myLibrary = new Library();
        myLibrary.AddBook(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925));
        myLibrary.AddBook(new Book("1984", "George Orwell", 1949));
        myLibrary.AddBook(new Book("To Kill a Mockingbird", "Harper Lee", 1960));

        // 通过字符串索引器访问
        Book gatsby = myLibrary["The Great Gatsby"];
        Console.WriteLine($"Found: {gatsby}"); // 输出: Found: The Great Gatsby by F. Scott Fitzgerald (1925)

        // 通过整数索引器访问
        Book firstBook = myLibrary[0];
        Console.WriteLine($"First book: {firstBook}"); // 输出: First book: The Great Gatsby by F. Scott Fitzgerald (1925)

        // 使用索引器更新书籍
        myLibrary["1984"] = new Book("Nineteen Eighty-Four", "George Orwell", 1949);
        Console.WriteLine($"Updated: {myLibrary["Nineteen Eighty-Four"]}"); // 输出: Updated: Nineteen Eighty-Four by George Orwell (1949)

        // 使用索引器添加书籍 (如果set逻辑支持)
        myLibrary["New Book Title"] = new Book("New Book Title", "New Author", 2023);
        Console.WriteLine($"Added: {myLibrary["New Book Title"]}"); // 输出: Added: New Book Title by New Author (2023)
    }
}

通过这个例子,你可以看到

Library
类的实例
myLibrary
现在可以像字典一样通过书名来获取
Book
对象,或者像列表一样通过数字索引来获取,这极大地提升了代码的可读性和直观性。

C#索引器与属性(Property)有何不同?何时该用索引器?

这确实是个常见的问题,很多人会觉得索引器和属性很像,都是通过

get/set
访问器来操作数据。但它们之间有个核心区别索引器是带参数的,而属性不带参数。

一个属性(Property)通常代表了对象的一个命名特性(named characteristic),比如

Book.Title
Book.Author
。你通过属性名直接访问它,每次访问都是针对该对象的一个特定、唯一的“值”。

public class Person
{
    public string Name { get; set; } // 属性
    public int Age { get; set; }     // 属性
}

而索引器则允许你通过一个或多个参数来访问对象内部的集合映射数据。它让类的实例表现得像一个数组、列表或字典,提供了一种“按位置”或“按键”访问其内部元素的机制。索引器没有显式的名字,而是通过

this
关键字和方括号
[]
来定义和使用。

何时选择使用索引器?

我觉得,当你的类本质上是一个某种元素的集合,或者它内部维护了一个可以通过某种键(不一定是整数)来查找的映射关系时,索引器就非常合适。

  1. 封装内部集合: 如果你的类内部有一个
    List
    Dictionary
    或其他集合类型,并且你希望外部代码能够直接通过索引(无论是数字索引还是键值索引)来操作这些内部元素,而不是暴露内部集合本身,那么索引器是理想的选择。这提供了更好的封装性
  2. 模拟数组/字典行为: 当你希望你的类实例能够像数组或字典一样被访问时。比如一个
    Matrix
    类,你可以通过
    matrix[row, col]
    来访问元素;或者一个
    Configuration
    类,你可以通过
    config["DatabaseConnectionString"]
    来获取配置值。
  3. 提供直观的API: 索引器让代码读起来更自然,更符合我们对集合操作的直觉。
    myLibrary["1984"]
    myLibrary.GetBookByTitle("1984")
    看起来更简洁,也更像语言内置的集合操作。

避免在以下情况使用索引器:

  • 当你的成员是一个单一、具名的值,而不是集合中的一个元素时,使用属性。
  • 当访问逻辑复杂到需要多个参数,且这些参数的组合不构成一个“索引”的概念时,考虑使用方法。

简单来说,如果你的类是“某种东西的集合”,索引器是你的朋友。如果你的类是“有这些特征的对象”,属性是你的朋友。

如何实现一个多参数或只读/只写索引器?有哪些高级用法?

索引器的灵活性远不止于此,你可以根据需求实现更复杂的行为。

多参数索引器:

英文企业网站管理系统
英文企业网站管理系统

英文企业网站管理系统(英文网站设计系统)采用主流的Asp+Access开发设计,开发新英文模板,漂亮大气。是方便自主管理的英文网站建设系统,程序小巧,速度快,后台一站式管理,代码功能全部开源,无任何限制。支持所有Asp虚拟空间,兼容良好,程序采用Div+Css设计,兼容ie6、ie7、ie8、火狐等英文浏览器,网站优化结构设计,配置网站地图,容易被搜索引擎收录,上关键词排名!欢迎大家使用。程序功能

下载

索引器可以接受一个或多个参数,参数类型也没有限制,可以是

int
,
string
,
Guid
, 甚至是你自定义的类型。这在处理多维数据结构时特别有用,比如矩阵或坐标系统。

public class Matrix
{
    private int[,] _data;
    private int _rows;
    private int _cols;

    public Matrix(int rows, int cols)
    {
        _rows = rows;
        _cols = cols;
        _data = new int[rows, cols];
    }

    // 多参数索引器,通过行和列访问矩阵元素
    public int this[int row, int col]
    {
        get
        {
            if (row >= 0 && row < _rows && col >= 0 && col < _cols)
            {
                return _data[row, col];
            }
            throw new IndexOutOfRangeException("矩阵索引超出范围。");
        }
        set
        {
            if (row >= 0 && row < _rows && col >= 0 && col < _cols)
            {
                _data[row, col] = value;
            }
            else
            {
                throw new IndexOutOfRangeException("矩阵索引超出范围,无法设置。");
            }
        }
    }
}

// 使用示例
public class MatrixProgram
{
    public static void Main(string[] args)
    {
        Matrix m = new Matrix(3, 3);
        m[0, 0] = 1;
        m[1, 1] = 5;
        m[2, 2] = 9;

        Console.WriteLine($"Matrix element (1,1): {m[1, 1]}"); // 输出: Matrix element (1,1): 5
    }
}

这里

this[int row, int col]
就是一个多参数索引器,它允许我们像操作二维数组一样操作
Matrix
对象。

只读或只写索引器:

就像属性一样,索引器也可以是只读(只有

get
访问器)或只写(只有
set
访问器)的。

  • 只读索引器: 当你只想提供一种通过索引查询数据的方式,而不允许外部修改时。

    public class ReadOnlyCollection
    {
        private List _items = new List();
    
        public ReadOnlyCollection(IEnumerable items)
        {
            _items.AddRange(items);
        }
    
        public T this[int index]
        {
            get
            {
                if (index >= 0 && index < _items.Count)
                {
                    return _items[index];
                }
                throw new IndexOutOfRangeException("索引超出范围。");
            }
            // 没有set访问器,所以是只读的
        }
    }
  • 只写索引器: 相对少见,但有时当你只想提供一种通过索引设置数据的方式,而不允许直接读取时可能会用到。例如,一个日志系统可能只允许你通过某个键写入日志条目,但不允许直接读取。

    public class LogWriter
    {
        private Dictionary _logs = new Dictionary();
    
        public string this[string key]
        {
            // 没有get访问器,所以是只写的
            set
            {
                _logs[key] = value;
                Console.WriteLine($"Log entry '{key}' set to: {value}");
            }
        }
    }

索引器重载:

你可以在同一个类中定义多个索引器,只要它们的参数签名(数量和类型)不同即可,这叫做索引器重载。就像

Library
示例中同时存在
this[string title]
this[int index]
。这提供了极大的灵活性,让你的类能以多种方式被“索引”。

在接口中定义索引器:

索引器也可以在接口中定义,强制实现该接口的类提供特定的索引行为。

public interface IIndexedCollection
{
    T this[int index] { get; set; }
}

public class MyList : IIndexedCollection
{
    private List _items = new List();

    public T this[int index]
    {
        get { return _items[index]; }
        set { _items[index] = value; }
    }

    public void Add(T item)
    {
        _items.Add(item);
    }
}

这让设计模式更加强大,能够统一不同集合类的访问方式。

总的来说,索引器是一个非常强大的语言特性,它能让你的自定义类型在处理集合数据时,拥有与内置集合类型相似的直观和简洁性。合理使用它,可以显著提升代码的可读性和维护性。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

381

2023.08.02

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

278

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1492

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

622

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

572

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

586

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

168

2025.07.29

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

25

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.5万人学习

C 教程
C 教程

共75课时 | 4.2万人学习

C++教程
C++教程

共115课时 | 13.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号