簡介
索引器(Indexer)是 C# 中的一種特殊屬性,它允許類或結構體像數組一樣使用索引語法(例如 obj[0])來訪問或修改對象內部的成員。簡單來説,它將對象的實例視為“可索引的集合”,提供類似於數組的訪問方式。
-
核心特性:
- 類似於屬性(
Property),但帶有參數(通常是索引值,如整數或字符串)。 - 支持
get和set訪問器,與屬性類似。 - 可以重載(
overload),允許不同類型的索引參數。 - 語法:
public 類型 this[參數類型 參數名] { get { ... } set { ... } }
- 類似於屬性(
- 適用範圍:類、結構體、接口。不能在委託或枚舉中使用。
索引器本質上是方法(get/set),但編譯器將其轉換為特殊的屬性調用,隱藏了底層實現細節。
語法結構:
public <返回類型> this[<參數類型> index]
{
get { ... }
set { ... }
}
this[...]表示作用於當前對象實例。- 可以有多個索引參數(如二維索引)。
為什麼使用索引器?
在面向對象編程中,直接暴露內部數組或集合(如 public int[] Data { get; })會破壞封裝性(客户端可隨意修改)。索引器提供受控訪問:
- 封裝性:隱藏內部存儲(如
List、Dictionary),允許驗證、轉換或緩存邏輯。 - 直觀性:代碼更像數組操作,提升可讀性(e.g.,
cache["key"] = value; 而非cache.Set("key", value);)。 -
適用場景:
- 模擬數組/集合(如自定義列表、矩陣)。
- 字典式訪問(字符串鍵)。
- 多維數據(如圖像像素訪問)。
- 與
LINQ或foreach集成(需實現IEnumerable)。
相比普通方法,索引器更簡潔;相比屬性,它支持參數化訪問。
基本示例
public class MyList
{
private string[] _data = new string[5];
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
使用方式:
var list = new MyList();
list[0] = "Hello";
list[1] = "World";
Console.WriteLine(list[0]); // 輸出:Hello
Console.WriteLine(list[1]); // 輸出:World
看起來就像數組訪問,但其實內部是屬性訪問。
索引器與屬性的關係
| 對比項 | 屬性 (Property) | 索引器 (Indexer) |
|---|---|---|
| 名稱 | 有名字 | 名為 this |
| 參數 | 無參數 | 有一個或多個參數 |
| 調用方式 | obj.Property |
obj[index] |
| 典型用途 | 訪問字段值 | 訪問集合或映射內容 |
索引器的底層機制
編譯後:
obj[index]
其實會被編譯為:
obj.get_Item(index); // 讀取
obj.set_Item(index, x); // 賦值
也就是説,索引器就是名為 Item 的一對 get/set 方法(CLR 級別)。
不同類型的索引器
整數索引器
public class IntArrayWrapper
{
private int[] _array;
public IntArrayWrapper(int size)
{
_array = new int[size];
}
public int this[int index]
{
get => _array[index];
set => _array[index] = value;
}
public int Length => _array.Length;
}
// 使用
var wrapper = new IntArrayWrapper(5);
wrapper[0] = 10;
wrapper[1] = 20;
Console.WriteLine(wrapper[0]); // 輸出: 10
字符串索引器
public class DictionaryWrapper
{
private Dictionary<string, string> _dictionary = new Dictionary<string, string>();
public string this[string key]
{
get
{
_dictionary.TryGetValue(key, out string value);
return value;
}
set
{
_dictionary[key] = value;
}
}
}
// 使用
var dictWrapper = new DictionaryWrapper();
dictWrapper["name"] = "John";
dictWrapper["age"] = "30";
Console.WriteLine(dictWrapper["name"]); // 輸出: John
多參數索引器
public class Matrix
{
private double[,] _matrix;
public Matrix(int rows, int columns)
{
_matrix = new double[rows, columns];
}
// 多參數索引器
public double this[int row, int column]
{
get => _matrix[row, column];
set => _matrix[row, column] = value;
}
public int Rows => _matrix.GetLength(0);
public int Columns => _matrix.GetLength(1);
}
// 使用
var matrix = new Matrix(3, 3);
matrix[0, 0] = 1.0;
matrix[1, 1] = 2.0;
matrix[2, 2] = 3.0;
Console.WriteLine(matrix[1, 1]); // 輸出: 2.0
重載索引器
public class MultiIndexCollection
{
private List<string> _items = new List<string>();
public void Add(string item) => _items.Add(item);
// 整數索引器
public string this[int index]
{
get => _items[index];
set => _items[index] = value;
}
// 字符串索引器 - 通過名稱查找
public string this[string name]
{
get => _items.Find(item => item.StartsWith(name));
}
}
// 使用
var collection = new MultiIndexCollection();
collection.Add("Apple");
collection.Add("Banana");
collection.Add("Cherry");
Console.WriteLine(collection[0]); // 輸出: Apple
Console.WriteLine(collection["B"]); // 輸出: Banana
高級用法
只讀索引器
public class Settings
{
private readonly Dictionary<string, string> _values = new();
public string this[string key]
{
get => _values.TryGetValue(key, out var value) ? value : string.Empty;
set => _values[key] = value;
}
}
使用:
var s = new Settings();
s["Language"] = "Chinese";
s["Theme"] = "Dark";
Console.WriteLine(s["Language"]); // Chinese
只寫:
public string this[int index]
{
set => _data[index] = value;
}
索引器可以被繼承或重寫
父類定義:
public class Base
{
public virtual string this[int index]
{
get => $"Base:{index}";
set => Console.WriteLine($"Set Base[{index}]={value}");
}
}
子類重寫:
public class Derived : Base
{
public override string this[int index]
{
get => $"Derived:{index}";
set => Console.WriteLine($"Set Derived[{index}]={value}");
}
}
接口中的索引器
public interface IListContainer<T>
{
T this[int index] { get; set; }
int Count { get; }
}
public class MyList<T> : IListContainer<T>
{
private List<T> _items = new List<T>();
public T this[int index]
{
get => _items[index];
set => _items[index] = value;
}
public int Count => _items.Count;
public void Add(T item) => _items.Add(item);
}
實際應用示例
配置管理器
public class Configuration
{
private readonly Dictionary<string, object> _settings = new Dictionary<string, object>();
public object this[string key]
{
get => _settings.TryGetValue(key, out object value) ? value : null;
set => _settings[key] = value;
}
public T Get<T>(string key, T defaultValue = default)
{
if (_settings.TryGetValue(key, out object value) && value is T typedValue)
{
return typedValue;
}
return defaultValue;
}
}
// 使用
var config = new Configuration();
config["DatabaseConnection"] = "Server=localhost;Database=Test;";
config["Timeout"] = 30;
string connection = config.Get<string>("DatabaseConnection");
int timeout = config.Get<int>("Timeout");
自定義集合類
public class SmartCollection<T>
{
private T[] _items;
public SmartCollection(int size) => _items = new T[size];
public T this[int index]
{
get => _items[index];
set => _items[index] = value;
}
// 重載索引器
public T this[string name] => FindByName(name);
private T FindByName(string name)
{
// 根據名稱查找邏輯...
}
}
數據訪問層封裝
public class DataRepository
{
private List<Customer> _customers = new();
public Customer this[int id]
{
get => _customers.FirstOrDefault(c => c.Id == id);
}
public Customer this[string email]
{
get => _customers.FirstOrDefault(c => c.Email == email);
}
}
索引器與其他特性結合
索引器與泛型
public class GenericCollection<T>
{
private T[] _items = new T[10];
public T this[int index]
{
get => _items[index];
set => _items[index] = value;
}
}
索引器與模式匹配(C# 8.0+)
if (collection is IIndexable<int, string> indexable)
{
Console.WriteLine(indexable[0]);
}
索引器與範圍支持(C# 8.0+)
public class RangeCollection
{
private int[] _items = {1, 2, 3, 4, 5};
public int[] this[Range range]
{
get => _items[range];
}
}
// 使用
var collection = new RangeCollection();
int[] sub = collection[1..4]; // [2, 3, 4]
常見應用場景
| 場景 | 示例 |
|---|---|
| 模擬集合/字典訪問 | myDict[key] |
| 操作二維數據 | matrix[row, col] |
| 管理配置項 | settings["Theme"] |
| 實現對象簡潔訪問接口 | student["Name"]、api["token"] |