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<Book> _books;
public Library()
{
_books = new List<Book>();
}
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
这确实是个常见的问题,很多人会觉得索引器和属性很像,都是通过
get/set
一个属性(Property)通常代表了对象的一个命名特性(named characteristic),比如
Book.Title
Book.Author
public class Person
{
public string Name { get; set; } // 属性
public int Age { get; set; } // 属性
}而索引器则允许你通过一个或多个参数来访问对象内部的集合或映射数据。它让类的实例表现得像一个数组、列表或字典,提供了一种“按位置”或“按键”访问其内部元素的机制。索引器没有显式的名字,而是通过
this
[]
何时选择使用索引器?
我觉得,当你的类本质上是一个某种元素的集合,或者它内部维护了一个可以通过某种键(不一定是整数)来查找的映射关系时,索引器就非常合适。
List<T>
Dictionary<K, V>
Matrix
matrix[row, col]
Configuration
config["DatabaseConnectionString"]
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 < _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<T>
{
private List<T> _items = new List<T>();
public ReadOnlyCollection(IEnumerable<T> 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<string, string> _logs = new Dictionary<string, string>();
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>
{
T this[int index] { get; set; }
}
public class MyList<T> : IIndexedCollection<T>
{
private List<T> _items = new List<T>();
public T this[int index]
{
get { return _items[index]; }
set { _items[index] = value; }
}
public void Add(T item)
{
_items.Add(item);
}
}这让设计模式更加强大,能够统一不同集合类的访问方式。
总的来说,索引器是一个非常强大的语言特性,它能让你的自定义类型在处理集合数据时,拥有与内置集合类型相似的直观和简洁性。合理使用它,可以显著提升代码的可读性和维护性。
以上就是C#的索引器是什么?如何使用?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号