C#矩阵类实现一维/二维索引器遇错误,求可行解决方案
嘿,这个问题我之前在做矩阵运算库的时候也纠结过!C#里确实没法直接给同一个类加两个参数个数相同但语义不同的索引器(比如同时用[int]表示行和列),不过有几个很实用的解决办法,给你梳理一下:
方案一:用自定义标记类型区分行/列索引
这个方法通过定义两个轻量的结构体来标记索引是行还是列,这样就能合法重载索引器了,语义也很清晰。
首先定义两个只读结构体(用结构体避免堆分配,性能更好):
// 标记这是行索引 public readonly struct RowIndex { public int Value { get; } public RowIndex(int value) => Value = value; } // 标记这是列索引 public readonly struct ColumnIndex { public int Value { get; } public ColumnIndex(int value) => Value = value; }
然后在你的Matrix类里新增两个索引器:
public class Matrix { private double[] _data; public int Rows { get; } public int Columns { get; } // 已有的二维索引器 public double this[int row, int col] { get => _data[row * Columns + col]; set => _data[row * Columns + col] = value; } // 行向量访问器:返回指定行的Vector public Vector this[RowIndex row] { get { var vector = new Vector(Columns); for (int col = 0; col < Columns; col++) { vector[col] = this[row.Value, col]; } return vector; } } // 列向量访问器:返回指定列的Vector public Vector this[ColumnIndex col] { get { var vector = new Vector(Rows); for (int row = 0; row < Rows; row++) { vector[row] = this[row, col.Value]; } return vector; } } // 可以加静态方法简化创建索引,不用每次new public static RowIndex Row(int index) => new RowIndex(index); public static ColumnIndex Col(int index) => new ColumnIndex(index); // 构造函数等其他代码... }
使用的时候就可以这样写,非常直观:
var matrix = new Matrix(3, 3); // 获取第2行(索引从0开始的话就是row=1) var rowVec = matrix[Matrix.Row(1)]; // 获取第3列 var colVec = matrix[Matrix.Col(2)];
方案二:拆分出专门的行/列访问器属性
如果觉得自定义标记类型有点麻烦,还可以给Matrix类加两个属性,分别返回行访问器和列访问器对象,用这些对象的索引器来获取向量:
public class Matrix { private double[] _data; public int Rows { get; } public int Columns { get; } // 已有的二维索引器 public double this[int row, int col] { get => _data[row * Columns + col]; set => _data[row * Columns + col] = value; } // 行访问器属性 public RowAccessor Rows => new RowAccessor(this); // 列访问器属性 public ColumnAccessor Cols => new ColumnAccessor(this); // 行访问器类 public class RowAccessor { private readonly Matrix _matrix; internal RowAccessor(Matrix matrix) => _matrix = matrix; public Vector this[int row] { get { var vector = new Vector(_matrix.Columns); for (int col = 0; col < _matrix.Columns; col++) { vector[col] = _matrix[row, col]; } return vector; } } } // 列访问器类 public class ColumnAccessor { private readonly Matrix _matrix; internal ColumnAccessor(Matrix matrix) => _matrix = matrix; public Vector this[int col] { get { var vector = new Vector(_matrix.Rows); for (int row = 0; row < _matrix.Rows; row++) { vector[row] = _matrix[row, col]; } return vector; } } } // 构造函数等其他代码... }
使用方式更贴近自然语义:
var matrix = new Matrix(3, 3); var rowVec = matrix.Rows[1]; var colVec = matrix.Cols[2];
方案三:简化版——默认一维索引为行,用方法获取列
如果你的场景里访问行的频率远高于列,或者想尽量简化代码,可以直接把this[int]重载为行访问,然后用一个方法来获取列向量:
public class Matrix { private double[] _data; public int Rows { get; } public int Columns { get; } // 已有的二维索引器 public double this[int row, int col] { get => _data[row * Columns + col]; set => _data[row * Columns + col] = value; } // 一维索引默认返回行向量 public Vector this[int row] { get { var vector = new Vector(Columns); for (int col = 0; col < Columns; col++) { vector[col] = this[row, col]; } return vector; } } // 用方法获取列向量 public Vector GetColumn(int col) { var vector = new Vector(Rows); for (int row = 0; row < Rows; row++) { vector[row] = this[row, col]; } return vector; } // 构造函数等其他代码... }
使用起来也很简单:
var matrix = new Matrix(3, 3); var rowVec = matrix[1]; var colVec = matrix.GetColumn(2);
总结一下
- 如果想要最严谨的语义区分,优先选方案一;
- 如果追求代码的可读性和自然语义,方案二是不错的选择;
- 如果场景简单,想快速实现,方案三最省事。
这些方案都能完美适配你把矩阵当行/列向量访问的需求,而且不会触发C#的索引器重载冲突~
内容的提问来源于stack exchange,提问作者wvn
相关产品推荐
相关产品推荐

