个人觉得,可能是为了尽可能减少并发问题。
可问题是局部变量中只是创建了一个新的地址啊,实际操作的还是堆上的真实数据啊,感觉完全没必要啊,还是说是我没理解你的意思啊,能详细说下吗
@WmW: 你这个是编译后被反编译过来的,你是用ILSpy看的吧,编译器会对源码做一定的优化。你看一下真正的源码,并非这样。https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646
@ensleep: 感谢,明白了,不过我不是题主啊,我只是个路过的 _
@ensleep: https://github.com/dotnet/runtime/blob/release/6.0/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
我看的源码和题主的一样 mark一下等一个解
@复制粘贴机器人:
谢谢你的代码,通过这个地址看到了这个源码。因为个人之前在处理类型并发问题中,对于值引用 和形参的代换情况接触得比较 多,所以,下面是个人对写这段代码的开发者的考虑做出主观猜测。从代码中,看得出,有多个地方对_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所指向的依然是旧的,虽然这次数据误写入了旧的中,丢失了,但是,并没有导致数据的破坏。
或许这就是开发人员虽然知道List不支持并发,但是,却也在努力尽最大可能降低不小心用在并发场景中对此带来的影响。