问题描述
为什么即使没有实现 setter 也可以设置二维数组?
这是我的代码。
public static void Main()
{
var obj = new TestObj();
obj.qwe[0,0] = 6;
obj.asd = 7; //error
Console.WriteLine(obj.qwe[0,0]); //6
}
public class TestObj
{
public int[,] qwe { get; } = new int[,] { { 1,2 },{ 3,4 },{ 5,6 },{ 7,8 } };
public int asd { get; } = 4;
}
解决方法
为什么即使没有实现 setter 也可以设置二维数组?
因为您没有设置属性,所以您正在更新数组中的一个项目。
例如,这不会编译:
obj.qwe = new int[0,0];
在您的代码中,您调用 get
以获取对数组的引用,并更新索引 0,0 处的项目:
obj.qwe[0,0] = 6;
,
属性 qwe
正在返回对数组内容的引用。这同样适用于一维或多维阵列。 C#中的所有数组都遵循引用语义
考虑以下内容
int[,] temp = obj.qwe; // property get
temp[0,0] = 6;
// obj.qwe[0,0] == 6
为了防止这种情况发生,您需要为二维数组创建一个包装类并实现一个索引器。
class Program
{
static void Main(string[] args)
{
IntArray obj = new int[,] { { 1,2 },{ 3,4 } };
int x = obj[0,0]; // ok,getter defined
obj[0,0] = 10; // error,no setter defined
int[,] objCopy = obj; // assignment to int[,] makes a copy
objCopy[0,0] = 10; // ok to modify copy
}
}
使用下面的整数数组包装类:
public class IntArray
{
readonly int[,] data;
public IntArray(int rows,int columns)
{
this.data = new int[rows,columns];
this.Rows = rows;
this.Columns = columns;
}
public IntArray(int[,] data)
{
this.data = data;
this.Rows = data.GetLength(0);
this.Columns = data.GetLength(1);
}
public int this[int row,int column]
{
// indexer getter
get => data[row,column];
}
public int Rows { get; }
public int Columns { get; }
public int[,] ToArray()
{
int[,] copy = new int[Rows,Columns];
Array.Copy(data,copy,data.Length);
return copy;
}
public static implicit operator IntArray(int[,] array)
=> new IntArray(array);
public static implicit operator int[,](IntArray obj)
=> obj.ToArray();
}
,
为什么会这样,其他人已经回答了。
为了使属性只读,我建议为二维数组创建自己的类。这允许您实现只读接口,并且相当容易做到:
public interface IReadOnlyArray2D<out T>
{
T this[int x,int y] { get; }
}
public class MyArray2D<T> : IReadOnlyArray2D<T>
{
public int Width { get; }
public int Height { get; }
public T[] Data { get; }
public MyArray2D(int width,int height )
{
this.Width = width;
this.Height = height;
Data = new T[width * height];
}
public T this[int x,int y]
{
get => Data[y * Width + x];
set => Data[y * Width + x] = value;
}
}
使用常规一维数组作为后备存储还有其他优点:
- 有时您只想处理所有项目,而不关心 x/y 坐标。
- 如果使用不当,多维数组有时会很慢。
- 互操作性通常更容易,因为更多系统在交换数据时使用一维数组或指针。
- 创建像
new T[width,height]
这样的多维数组将按列优先顺序存储它,而大多数类似图像的数据通常按行优先顺序存储。