为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
繁华开满天机 2023-07-09 16:13:19
我有一个要修改的元组列表。    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];
查看完整描述

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


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


查看完整回答
反对 回复 2023-07-09
?
慕妹3242003

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);

查看完整回答
反对 回复 2023-07-09
  • 2 回答
  • 0 关注
  • 115 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信