首页 新闻 会员 周边

c#的list类源码问题

0
悬赏园豆:5 [待解决问题]

Mad_Rabbit的主页 Mad_Rabbit | 菜鸟二级 | 园豆:307
提问于:2022-10-16 11:48
< >
分享
所有回答(1)
0

个人觉得,可能是为了尽可能减少并发问题。

ensleep | 园豆:1682 (小虾三级) | 2022-10-17 08:24

可问题是局部变量中只是创建了一个新的地址啊,实际操作的还是堆上的真实数据啊,感觉完全没必要啊,还是说是我没理解你的意思啊,能详细说下吗

支持(0) 反对(0) WmW | 园豆:424 (菜鸟二级) | 2022-10-17 09:28

@WmW: 你这个是编译后被反编译过来的,你是用ILSpy看的吧,编译器会对源码做一定的优化。你看一下真正的源码,并非这样。https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

支持(0) 反对(0) ensleep | 园豆:1682 (小虾三级) | 2022-10-17 12:44

@ensleep: 感谢,明白了,不过我不是题主啊,我只是个路过的 _

支持(0) 反对(0) WmW | 园豆:424 (菜鸟二级) | 2022-10-17 15:30

@复制粘贴机器人:
谢谢你的代码,通过这个地址看到了这个源码。因为个人之前在处理类型并发问题中,对于值引用 和形参的代换情况接触得比较 多,所以,下面是个人对写这段代码的开发者的考虑做出主观猜测。从代码中,看得出,有多个地方对_item进行了直接赋值操作,包括多个构造函数(这个不重要)以及修改长度,代码如下:

        public int Capacity
        {
            get => _items.Length;
            set
            {
                if (value < _size)
                {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
                }

                if (value != _items.Length)
                {
                    if (value > 0)
                    {
                        T[] newItems = new T[value];
                        if (_size > 0)
                        {
                            Array.Copy(_items, newItems, _size);
                        }
                        _items = newItems;
                    }
                    else
                    {
                        _items = s_emptyArray;
                    }
                }
            }
        }
		public void Add(T item)
        {
            _version++;
            T[] array = _items;
            int size = _size;
            if ((uint)size < (uint)array.Length)
            {
                _size = size + 1;
                array[size] = item;
            }
            else
            {
                AddWithResize(item);
            }
        }

我觉得这里是重点,新加元素时如果超出预设长度,也会触发修改这个Capacity,导致_items = newItems的操作。
也就是说,Add操作时,会有一定概率触发_items = newItems的操作。
当两个线程同时进行操作时,就会面临其中一个_items = newItems的情况,这种情况,直接操作_items时,可能会在(uint)size < (uint)array.Length判断完成后,执行array[size] = item;将数据误写入新的newItems中了。而如果用T[] array = _items;的话,即使_items = newItems在别的线程中被执行了,array所指向的依然是旧的,虽然这次数据误写入了旧的中,丢失了,但是,并没有导致数据的破坏。

支持(0) 反对(0) ensleep | 园豆:1682 (小虾三级) | 2022-10-17 15:59

或许这就是开发人员虽然知道List不支持并发,但是,却也在努力尽最大可能降低不小心用在并发场景中对此带来的影响。

支持(0) 反对(0) ensleep | 园豆:1682 (小虾三级) | 2022-10-17 16:01
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册