这是我的课:
class MyArray<T>
{
private T[] data;
public MyArray(int size)
{
data = new T[size];
}
public MyArray(in T[] array)
{
data = new T[array.Length];
for (int i = 0; i < array.Length; i++)
data[i] = array[i];
}
public T this[int i] //I am talking about this indexer
{
get => data[i];
set => data[i] = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我应该像这样定义我的索引器,而不是像上面那样做吗?
public ref T this[int i]
{
get => data[i];
}
Run Code Online (Sandbox Code Playgroud)
我应该选择哪种方法?据我所知,方法 1 允许您在设置值时执行额外的代码,但是方法 2 允许您执行类似的操作int.TryParse(str, out myArrayObj[i]);
编辑:这个问题不仅适用于索引器,而且适用于一般的任何属性。
TL;DR如果您需要 setter,那么您必须使用常规索引器,因为ref属性不能有 setter。如果不需要设置器,那么我总是会在泛型ref类型参数的索引器/属性中指定关键字,因为它们可以是值类型。是否通过引用访问它们取决于消费者。
ref如果类型参数是引用类型(类),关键字不会提供任何好处,但对于值类型会有所不同,因为它们可以直接访问而无需复制。因此,如果您想访问数组中的原始值,则必须使用ref关键字。如果您想访问数组中传递给类的值MyArray<T>,那么您不应该将这些值复制到其他私有数组,因为在这种情况下,您将获得私有数组中值的副本。
以下示例显示了 ref 访问与常规访问的不同之处:
[Fact]
public void ArrayTest()
{
var structs = new[] {new MyStruct()};
structs[0].Type++;
ref var @struct = ref structs[0];
@struct.Type++;
// Test passes the value was incremented twice, because reference was used.
structs[0].Type.Should().Be(2);
}
[Fact]
public void MyArrayTest()
{
var structs = new MyArray<MyStruct>(new[] {new MyStruct()});
// Compiler error, but was possible in earlier versions of C#
// and would not modify the item in the array,
// because value was copied before modification.
// structs[0].Type++;
var @struct = structs[0];
@struct.Type++;
// Value wasn't incremented, because it was copied on the stack.
structs[0].Type.Should().Be(0);
}
[Fact]
public void MyRefArrayTest()
{
var structs = new MyRefArray<MyStruct>(new[] {new MyStruct()});
structs[0].Type++;
ref var @struct = ref structs[0];
@struct.Type++;
// Test passes the value was incremented twice, because reference was used.
structs[0].Type.Should().Be(2);
}
struct MyStruct
{
public int Type { get; set; }
}
class MyArray<T>
{
private T[] data;
public MyArray(in T[] array)
{
data = new T[array.Length];
Array.Copy(array, data, array.Length);
}
public T this[int i]
{
get => data[i];
set => data[i] = value;
}
}
class MyRefArray<T>
{
private T[] data;
public MyRefArray(in T[] array)
{
data = new T[array.Length];
Array.Copy(array, data, array.Length);
}
public ref T this[int i]
{
get => ref data[i];
// Compiler error, ref indexer cannot have setter.
// set => data[i] = value;
}
}
Run Code Online (Sandbox Code Playgroud)