首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 索引器與運算子多載深度解析:語法、IL 實作與進階應用

     編輯:關於C#

前言

索引器讓物件像陣列一樣存取,運算子多載讓自訂型別支援數學/邏輯運算。兩者本質都是方法的語法糖,編譯為特定命名的方法。本文從語法、IL 實作、多載規則、進階應用全方位解析。

一、索引器

1.1 語法與編譯結果


public class BitArray
{
    private int[] _bits;
    private int _length;

    public BitArray(int length)
    {
        _length = length;
        _bits = new int[(length - 1) >> 5 + 1];
    }

    // 索引器宣告
    public bool this[int index]
    {
        get
        {
            if (index < 0 || index >= _length) throw new IndexOutOfRangeException();
            return (_bits[index >> 5] & (1 << index)) != 0;
        }
        set
        {
            if (index < 0 || index >= _length) throw new IndexOutOfRangeException();
            if (value) _bits[index >> 5] |= 1 << index;
            else _bits[index >> 5] &= ~(1 << index);
        }
    }
}

// 編譯為 IL 相當於:
// public bool get_Item(int index) { ... }
// public void set_Item(int index, bool value) { ... }

1.2 索引器特性

  • 名稱固定為 this,無自訂名稱
  • 至少一個參數,參數只能是 in/ref/out 不可用
  • 可多載:參數型別/數量不同即可
  • 存取修飾詞套用於整個索引器,get/set 可個別限制 (如 public int this[int i] { get; private set; })
  • 不可為 static (屬於實例)
  • 介面可宣告索引器,實作類別隱式/顯式實作

1.3 多參數索引器 (矩陣、稀疏陣列)


public class Matrix
{
    private double[,] _data;
    public Matrix(int rows, int cols) => _data = new double[rows, cols];

    public double this[int row, int col]
    {
        get => _data[row, col];
        set => _data[row, col] = value;
    }
}

// 使用
var m = new Matrix(3, 3);
m[1, 2] = 3.14;
double val = m[1, 2];

1.4 索引器與繼承


public class Base
{
    public virtual string this[int i] => $"Base[{i}]";
}

public class Derived : Base
{
    // 覆寫需使用 override
    public override string this[int i] => $"Derived[{i}]";
    
    // 新增多載
    public string this[string key] => $"Key:{key}";
}

// 基底索引器存取
var d = new Derived();
Console.WriteLine(d[0]);        // Derived[0]
Console.WriteLine(((Base)d)[0]); // Base[0]
// 或內部使用 base[0]

二、運算子多載

2.1 規則總覽

分類可多載運算子參數數量回傳型別限制
一元+ - ! ~ ++ -- true false1++/-- 必須同類別;true/false 必須為 bool 且成對出現
二元+ - * / % & | ^ << >> == != > < >= <=2至少一個參數為宣告類別;==/!=、>/<、>=/<= 必須成對
轉換implicit / explicit1參數與回傳型別必須不同,且至少一個為宣告類別;不可為 object/interface;不可有繼承關係

2.2 必須條件

  • public static 修飾
  • 參數不可為 ref/out
  • 不可為 virtual/abstract/override/sealed

2.3 複數類別完整範例


public readonly struct Complex : IEquatable
{
    public double Real { get; }
    public double Imag { get; }

    public Complex(double real, double imag) => (Real, Imag) = (real, imag);

    // 二元運算子
    public static Complex operator +(Complex a, Complex b) => new(a.Real + b.Real, a.Imag + b.Imag);
    public static Complex operator -(Complex a, Complex b) => new(a.Real - b.Real, a.Imag - b.Imag);
    public static Complex operator *(Complex a, Complex b) => 
        new(a.Real * b.Real - a.Imag * b.Imag, a.Real * b.Imag + a.Imag * b.Real);
    public static Complex operator /(Complex a, Complex b)
    {
        double denom = b.Real * b.Real + b.Imag * b.Imag;
        return new((a.Real * b.Real + a.Imag * b.Imag) / denom,
                   (a.Imag * b.Real - a.Real * b.Imag) / denom);
    }

    // 一元運算子
    public static Complex operator -(Complex a) => new(-a.Real, -a.Imag); // 取負
    public static Complex operator ++(Complex a) => new(a.Real + 1, a.Imag + 1); // 自增 (邏輯自訂)

    // 比較運算子 (成對)
    public static bool operator ==(Complex a, Complex b) => a.Equals(b);
    public static bool operator !=(Complex a, Complex b) => !a.Equals(b);

    // 隱式/顯式轉換
    public static implicit operator Complex(double d) => new(d, 0);      // double -> Complex
    public static explicit operator double(Complex c) => c.Magnitude;    // Complex -> double (需強制轉型)

    // 物件相等
    public bool Equals(Complex other) => Real == other.Real && Imag == other.Imag;
    public override bool Equals(object obj) => obj is Complex c && Equals(c);
    public override int GetHashCode() => HashCode.Combine(Real, Imag);

    public double Magnitude => Math.Sqrt(Real * Real + Imag * Imag);
    public override string ToString() => $"{Real} + {Imag}i";
}

// 使用
var a = new Complex(3, 4);
var b = new Complex(1, 2);
var c = a + b;        // 4 + 6i
var d = -a;           // -3 - 4i
var e = a * b;        // -5 + 10i
bool eq = a == b;     // false
Complex f = 5.0;      // 隱式轉換 5 + 0i
double mag = (double)f; // 顯式轉換 5.0

2.4 運算子多載陷阱

  • 參數不可變:運算子應回傳新例項,不可修改參數 (特別是結構體傳值複製)
  • 前置/後置 ++/--:編譯器自動處理,a++ 回傳舊值,++a 回傳新值,兩者呼叫同一個 operator++
  • true/false 運算子:支援 &&/|| 短路邏輯,必須成對定義,回傳 bool
  • 轉換運算子衝突:不可對同一對型別同時定義 implicit 和 explicit;不可與內建轉換衝突 (如 int->long)

三、進階應用:結合索引器與運算子

3.1 向量類別


public class Vector
{
    private readonly double[] _components;
    public int Dimension => _components.Length;

    public Vector(params double[] components) => _components = components ?? throw new ArgumentNullException();

    // 索引器
    public double this[int i]
    {
        get => _components[i];
        set => _components[i] = value;
    }

    // 運算子
    public static Vector operator +(Vector a, Vector b)
    {
        if (a.Dimension != b.Dimension) throw new InvalidOperationException("維度不符");
        var result = new double[a.Dimension];
        for (int i = 0; i < a.Dimension; i++) result[i] = a[i] + b[i];
        return new Vector(result);
    }

    public static Vector operator *(Vector v, double scalar)
    {
        var result = new double[v.Dimension];
        for (int i = 0; i < v.Dimension; i++) result[i] = v[i] * scalar;
        return new Vector(result);
    }

    public static double operator *(Vector a, Vector b) // 內積
    {
        if (a.Dimension != b.Dimension) throw new InvalidOperationException("維度不符");
        double sum = 0;
        for (int i = 0; i < a.Dimension; i++) sum += a[i] * b[i];
        return sum;
    }
}

3.2 矩陣乘法運算子


public class Matrix
{
    private readonly double[,] _data;
    public int Rows => _data.GetLength(0);
    public int Cols => _data.GetLength(1);

    public Matrix(int rows, int cols) => _data = new double[rows, cols];
    public Matrix(double[,] data) => _data = data;

    public double this[int r, int c] { get => _data[r, c]; set => _data[r, c] = value; }

    public static Matrix operator *(Matrix a, Matrix b)
    {
        if (a.Cols != b.Rows) throw new InvalidOperationException("矩陣維度不符");
        var result = new Matrix(a.Rows, b.Cols);
        for (int i = 0; i < a.Rows; i++)
            for (int j = 0; j < b.Cols; j++)
                for (int k = 0; k < a.Cols; k++)
                    result[i, j] += a[i, k] * b[k, j];
        return result;
    }
}

四、總結與最佳實務

特性索引器運算子多載
本質get_Item/set_Item 方法op_Addition/op_Implicit 等特殊名稱方法
適用場景集合存取、矩陣、字典語意數值型別、領域模型、DSL
多載依據參數簽名運算子符號 + 參數型別
介面支援可在介面宣告不可在介面宣告 (C# 11+ static abstract 除外)
慣例引數驗證拋 IndexOutOfRangeException回傳新例項、不可修改參數

設計原則:索引器提供「容器存取」語意,運算子提供「數學/邏輯運算」語意。濫用會導致程式碼難讀 (如 customer + order 語意不明)。僅在型別具有明確數學結構 (向量、矩陣、複數、單位量) 或容器語意 (List、Dictionary、BitArray) 時使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved