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

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 = 0 && 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

关键字和方括号

[]

来定义和使用。

何时选择使用索引器?

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

封装内部集合: 如果你的类内部有一个

List

Dictionary

或其他集合类型,并且你希望外部代码能够直接通过索引(无论是数字索引还是键值索引)来操作这些内部元素,而不是暴露内部集合本身,那么索引器是理想的选择。这提供了更好的封装性模拟数组/字典行为: 当你希望你的类实例能够像数组或字典一样被访问时。比如一个

Matrix

类,你可以通过

matrix[row, col]

来访问元素;或者一个

Configuration

类,你可以通过

config["DatabaseConnectionString"]

来获取配置值。提供直观的API: 索引器让代码读起来更自然,更符合我们对集合操作的直觉。

myLibrary["1984"]

myLibrary.GetBookByTitle("1984")

看起来更简洁,也更像语言内置的集合操作。

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

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

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

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

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

多参数索引器:

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

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 = 0 && col = 0 && row = 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);    }}

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

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

以上就是C#的索引器是什么?如何使用?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1439406.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 16:10:28
下一篇 2025年12月17日 16:10:38

相关推荐

  • C#的泛型集合在桌面开发中有何优势?

    C#泛型集合通过消除装箱拆箱提升性能与内存效率,保障编译时类型安全以减少运行时错误,并广泛应用于复杂数据结构及LINQ查询中,显著增强代码可读性与数据处理能力。 C#的泛型集合在桌面开发中,我个人觉得,简直是生产力的一大飞跃。它不仅仅是语言特性上的一个进步,更是实实在在地解决了我们日常开发中遇到的许…

    2025年12月17日
    000
  • ASP.NET Core中的应用程序部件是什么?如何使用?

    应用程序部件通过扩展ASP.NET Core的组件发现机制,解决模块化应用中控制器或视图无法被自动扫描的问题。默认情况下,运行时仅扫描主程序集,而ApplicationPartManager允许显式注册额外程序集(如类库),使其包含的MVC组件(控制器、视图等)可被发现和使用。最常见的类型是Asse…

    2025年12月17日
    000
  • 如何实现WinForms控件的双缓冲绘制?

    最直接有效的方法是将控件的DoubleBuffered属性设置为true,可消除界面闪烁;对于复杂场景,可使用BufferedGraphicsContext和BufferedGraphics进行精细控制,先在内存中完成绘制再一次性呈现。 在WinForms中实现控件的双缓冲绘制,最直接有效的方法就是…

    2025年12月17日
    000
  • OverflowException是什么?如何检查数值溢出?

    overflowexception是当算术运算或类型转换结果超出目标数据类型范围时抛出的异常;2. 数值溢出因固定位数存储限制导致,常见表现为“回绕”,如int.maxvalue + 1在unchecked下变为int.minvalue;3. c#中可用checked关键字强制检查溢出并抛出异常,u…

    2025年12月17日
    000
  • BroadcastBlock的消息丢失异常怎么处理?

    broadcastblock消息丢失的核心原因是其“尽力而为”的设计哲学,优先保证高吞吐和低延迟,而非消息可靠性;2. 主要成因包括下游消费者处理速度慢导致背压、boundedcapacity设置不当引发缓冲区满载、下游块因异常断开连接或处理失败;3. 解决方案首先是优化下游处理能力,通过设置max…

    2025年12月17日
    000
  • C#的COM互操作是什么?如何使用?

    C#的COM互操作是.NET与COM组件间通信的桥梁,通过引用COM类型库生成互操作程序集,利用RCW实现托管与非托管代码调用,常用于集成遗留系统、Office自动化及系统级功能访问;使用时需注意Type.Missing传参、按顺序调用Marshal.ReleaseComObject释放对象以避免内…

    2025年12月17日
    000
  • C语言中指针怎么使用C语言指针的基本概念和常见错误

    c语言的指针本质是内存地址,理解这一点后,指针的核心作用在于直接操作内存。1. 指针的基本操作包括声明、赋值和解引用;2. 指针与数组关系密切,数组名即为指向首元素的指针;3. 使用指针需避免空悬指针、野指针和内存泄漏等常见错误;4. 指针运算应注意仅对同一数组内有效且步长由数据类型决定;5. 利用…

    2025年12月17日 好文分享
    000
  • WinForms的PictureBox怎么实现缩放与滚动?

    核心是通过Matrix类对PictureBox的Image进行缩放变换,并用滚动条控制偏移实现滚动。需维护原始图像、当前缩放比例和偏移量,响应鼠标滚轮或按钮调整scale值,结合Graphics的Transform和TranslateTransform实现高效绘制。 PictureBox的缩放与滚动…

    2025年12月17日
    000
  • C#的本地化与全球化在桌面端如何实现?

    C#桌面端的本地化与全球化通过System.Globalization和System.Resources实现,核心是使用.resx资源文件存储多语言字符串,ResourceManager根据CultureInfo加载对应语言资源,支持动态切换文化、格式化日期货币,并可通过命名策略、复数规则处理和伪本…

    2025年12月17日
    000
  • C#的Process的异常处理有什么注意事项?

    启动Process失败通常因文件不存在或权限不足,可通过Win32Exception的ErrorCode判断:2表示文件未找到,5表示拒绝访问;执行超时可用WaitForExit(int)配合Kill()处理;监控输出需重定向流并使用异步事件读取;权限问题可通过Verb=”runas&#…

    2025年12月17日
    000
  • C#的迭代器是什么?如何使用?

    答案:C#迭代器通过yield return实现惰性求值,支持按需生成值,节省内存;可使用方法或自定义类实现,结合IEnumerable和IEnumerator接口控制遍历过程;在LINQ中实现延迟执行,提升性能;可通过try-catch处理异常,确保迭代继续;yield return自动管理状态,…

    2025年12月17日
    000
  • ASP.NET Core中的资源筛选器是什么?如何创建?

    资源筛选器是ASP.NET Core中最早执行的过滤器,作用于MVC请求管道,可用于缓存、授权、日志等全局任务,通过实现IResourceFilter接口或继承Attribute类创建,支持依赖注入,适用于需在控制器前后执行且与MVC上下文交互的场景。 资源筛选器,简单来说,就是ASP.NET Co…

    2025年12月17日
    000
  • C#的ActionResult是什么?有哪些类型?

    ActionResult是ASP.NET Core中表示控制器执行结果的抽象基类,通过其派生类或IActionResult接口实现多样化HTTP响应,如视图渲染、JSON数据返回、文件下载等,框架负责将其转换为实际响应;优先推荐使用IActionResult作为返回类型以提升灵活性和可维护性,因其支…

    2025年12月17日
    000
  • C#的委托与事件在桌面开发中怎么用?

    委托是类型安全的函数指针,事件基于委托实现发布/订阅模式,二者在桌面应用中实现松散耦合的通信。通过定义方法签名,委托可封装并传递方法,用于跨线程调用如Control.Invoke或Dispatcher.BeginInvoke,确保UI更新安全。事件则用于通知状态变化,如按钮点击或值更改,支持组件间解…

    2025年12月17日
    000
  • C#的KeyNotFoundException是什么?字典键缺失处理

    解决方案是优先使用trygetvalue避免异常,因为它在一次查找中完成存在性检查和值获取,性能更优;2. 当仅需判断键是否存在而无需值时,使用containskey更合适;3. 可通过扩展方法如getvalueordefault提供默认值,使代码更简洁;4. 若必须捕获keynotfoundexc…

    2025年12月17日
    000
  • 如何实现WinForms应用的单一实例运行?

    使用命名互斥量(Mutex)实现WinForms应用单一实例,通过唯一GUID标识应用;2. 启动时尝试创建Mutex,若已存在则说明有实例运行;3. 检测到重复实例时,通过Process获取同名进程并获取其主窗口句柄;4. 调用user32.dll的IsIconic、ShowWindow和SetF…

    2025年12月17日
    000
  • C#的文件操作是什么?如何读写文件?

    C#文件操作核心是通过System.IO命名空间中的File、StreamReader、StreamWriter和FileStream等类实现文本和二进制文件的读写。1. File类适用于简单场景,提供ReadAllText和WriteAllText等静态方法进行整体读写;2. StreamRead…

    2025年12月17日
    000
  • C#的异步编程模式是什么?如何实现?

    答案是基于async和await的TAP模式是C#推荐的异步编程方式,它通过非阻塞I/O提升响应性和吞吐量,适用于I/O密集型操作,结合Task.Run可处理CPU密集型任务,相比传统多线程更简洁高效,避免回调地狱,需注意async void、ConfigureAwait和异常处理等最佳实践。 C#…

    2025年12月17日
    000
  • MemberAccessException在反射中怎么捕获?成员访问异常

    memberaccessexception的捕获方式是通过try-catch语句块实现,需预判可能触发异常的反射操作并包裹处理逻辑;2. 该异常通常因访问私有、受保护成员或安全策略限制而发生,现代.net中更多由其派生类如fieldaccessexception抛出;3. 常见原因是bindingf…

    2025年12月17日
    000
  • .NET的AssemblyDefaultAliasAttribute类的作用是什么?

    AssemblyDefaultAliasAttribute用于为程序集指定一个默认别名,主要在COM互操作等特定场景中提供简洁、易识别的名称替代冗长的强名称,如将“MyCompany.MyProduct.CoreServices…”简化为“DataProcessorCore”;它属于程序…

    2025年12月17日
    000

发表回复

登录后才能评论
关注微信