我可以通过引用返回来获取列表项吗?

Ste*_*lis 5 c#

我有一个要修改的元组列表。

    var myList = new List<(int head, int[] tail)> {
        (0, new[] { 1, 2, 3 }),
        (7, new[] { 8, 9 }   ), };
    var myArray = new (int head, int[] tail)[] {
        (0, new[] { 1, 2, 3 }),
        (7, new[] { 8, 9 }   ), };

    // ...

    // ref var firstElement = ref myList[0];
    ref var firstElement = ref myArray[0];
    firstElement.head = 99;
Run Code Online (Sandbox Code Playgroud)

这非常适合数组,但不适用于列表。我知道这是因为索引器不执行引用返回;但是列表是否可以通过其他方式通过引用返回其元素,以便我可以修改返回的元组?

这将导致编译器错误“属性或索引器可能无法作为 out 或 ref 参数传递”:

ref var firstElementList = ref myList[0];
Run Code Online (Sandbox Code Playgroud)

Vik*_*nov 3

据我了解,发生这种情况是因为编译器知道数组并且不会为其调用索引器。根据 MSDN 的说法,对于列表,它调用索引器,而对于索引器,您不能使用 ref(索引器签名中没有 ref)。

为了这

 var firstElement = myArray[0];

 firstElement.head = 99;
Run Code Online (Sandbox Code Playgroud)

Ildasm 展示了这一点

ldelem     valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>
Run Code Online (Sandbox Code Playgroud)

微软软件定义网络

即IL 级别支持数组。

而对于列表,它调用索引器。

 callvirt   instance !0 class [System.Collections]System.Collections.Generic.List`1<valuetype [System.Runtime]System.ValueTuple`2<int32,int32[]>>::get_Item(int32)
Run Code Online (Sandbox Code Playgroud)

对于索引器来说,如果您将 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();
}
Run Code Online (Sandbox Code Playgroud)

PS但是当你开始实现你自己的列表实现(作为数组列表)时,你可能会注意到,不值得拥有引用索引器 - 想象你调整了数组的大小 - 创建了新的数组并复制了所有数据;这意味着某人可能持有非实际参考。

PPS 更进一步,假设我们创建链接列表 - 只是调整大小不会发生任何错误,但想象我们删除了某人持有引用的元素 - 不可能理解它不再属于列表。

所以,是的,我认为他们故意将列表索引器设置为非引用,因为对于可以更改的内容返回引用似乎不是一个好主意。