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

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


    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;

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


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


ref var firstElementList = ref myList[0];


繁华开满天机
浏览 116回答 2
2回答

翻翻过去那场雪

据我了解,发生这种情况是因为编译器知道数组并且不会为其调用索引器。根据 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 更进一步,假设我们创建链接列表 - 只是调整大小不会发生任何错误,但想象我们删除了某人持有引用的元素 - 不可能理解它不再属于列表。所以,是的,我认为他们故意将列表索引器设置为非引用,因为对于可以更改的内容返回引用似乎不是一个好主意。

慕妹3242003

您可以使用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);
打开App,查看更多内容
随时随地看视频慕课网APP