为什么即使 setter 未实现也可以设置二维数组
Why is it possible to set a 2d array even if setter not implemented
为什么即使 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;
}
Why is it possible to set a 2d array even if the setter not implemented?
因为您没有设置 属性,所以您正在更新数组中的项目。
例如,这不会编译:
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 并实现一个索引器。
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
}
}
使用下面的整数数组包装器 class:
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();
}
为什么会这样,其他人已经回答过了
要使 属性 只读,我建议为二维数组创建您自己的 class。这允许您实现一个只读接口,而且相当容易做到:
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]
这样的多维数组将按列优先顺序存储它,而大多数类似图像的数据通常按行优先顺序存储。
为什么即使 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;
}
Why is it possible to set a 2d array even if the setter not implemented?
因为您没有设置 属性,所以您正在更新数组中的项目。
例如,这不会编译:
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 并实现一个索引器。
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
}
}
使用下面的整数数组包装器 class:
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();
}
为什么会这样,其他人已经回答过了
要使 属性 只读,我建议为二维数组创建您自己的 class。这允许您实现一个只读接口,而且相当容易做到:
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]
这样的多维数组将按列优先顺序存储它,而大多数类似图像的数据通常按行优先顺序存储。