2 回答
TA贡献2065条经验 获得超13个赞
据我了解,发生这种情况是因为编译器知道数组并且不会为其调用索引器。根据 MSDN 的说法,对于列表,它调用索引器,而对于索引器,您不能使用 ref(索引器签名中没有 ref)。
为了这
var firstElement = myArray[0];
firstElement.head = 99;
Ildasm 展示了这一点
ldelem valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>
微软软件定义网络
即IL 级别支持数组。
而对于列表,它调用索引器。
callvirt instance !0 class [System.Collections]System.Collections.Generic.List`1<valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>>::get_Item(int32)
对于索引器来说,如果您将 ref 放入签名中,它就可以工作。
例如(仅用于演示目的;是的,应该有数组而不是单个变量等,但只是为了使其可编译)
class Program
{
static void Main(string[] args)
{
var myList = new MyList<(int head, int[] tail)> {
(0, new[] { 1, 2, 3 }),
(7, new[] { 8, 9 } ), };
ref var firstElement = ref myList[0];
firstElement.head = 99;
Console.WriteLine("Hello World!");
}
}
public class MyList<T> : IEnumerable
{
private T value;
public ref T this[int index]
{
get
{
return ref value;
}
}
public void Add(T i)
{
value = i;
}
public IEnumerator GetEnumerator() => throw new NotImplementedException();
}
PS但是当你开始实现你自己的列表实现(作为数组列表)时,你可能会注意到,不值得拥有引用索引器 - 想象你调整了数组的大小 - 创建了新的数组并复制了所有数据;这意味着某人可能持有非实际参考。
PPS 更进一步,假设我们创建链接列表 - 只是调整大小不会发生任何错误,但想象我们删除了某人持有引用的元素 - 不可能理解它不再属于列表。
所以,是的,我认为他们故意将列表索引器设置为非引用,因为对于可以更改的内容返回引用似乎不是一个好主意。
TA贡献1824条经验 获得超6个赞
您可以使用WeakReference并更改ValueTuple为类来执行此操作:
List<MyClass> myList = new List<MyClass> {
new MyClass { Head = 0, Tail = new[] { 1, 2, 3 } },
new MyClass { Head = 7, Tail = new[] { 8, 9 } } };
var firstElement = new WeakReference(myList[0]);
MyClass reference = firstElement.Target as MyClass;
reference.Head = 99;
firstElement.Target = new MyClass { Head = 99, Tail = reference.Tail};
Console.WriteLine(myList[0].Head);
- 2 回答
- 0 关注
- 115 浏览
添加回答
举报