Список показывает 4 элемента в отладчике, даже если они заполнены ровно одним элементом
Когда я просматриваю список, заполненный отдельным элементом в отладчике, его поле _items
содержит 4 элемента. Можете ли вы объяснить поведение?
Я обнаружил, что при отладке моего консольного приложения узнать о Distinct
и ToList
и результат меня смущает. Код:
List<int> nums = new List<int>() { 6, 6, 6, 6, 6, 6, 6, 6 };
List<int> distinctNums = nums.Distinct().ToList();
int[] distinctNums2 = nums.Distinct().ToArray();
-
distinctNums
имеет 4 элемента в _items
: (6, 0, 0, 0)
, что явно неверно.
-
distinctNums2
имеет 1 элемент (6)
, который является правильным.
Ответы
Ответ 1
Это создаст список distinctNums
, который содержит только один элемент, как и следовало ожидать. Однако списки в .NET поддерживаются массивом, который автоматически изменяется при добавлении к нему элементов. Этот массив начинается с размера 4, поэтому внутренний массив будет [4, 0, 0, 0]
, если вы проведете его через отражение или в отладчике.
Но если вы проверите, вы найдете distinctNums.Count == 1
. Сравните Count
и Capacity
свойства.
Ответ 2
Оба distinctNums
и distinctNums2
действительно содержат только один объект.
Список с четырьмя элементами, которые вы видите в отладчике, - это только массив, который поддерживает List<int>
. Вы можете видеть, что его Count
- 1
, и если вы переименовываете список, он возвращает только один 6
.
Ответ 3
List<T>
- абстракция сверху T[]
(стандартный массив). Размер массива не имеет значения. Когда вы выделяете List<T>
одним элементом, компилятор не выделяет new T[1]
, он дает вам некоторое пространство для роста (он должен перераспределять новый массив и копировать элементы, когда вы перерастаете оригинал, который является относительно дорогой операцией). Count
дает вам длину списков, и если вы вызываете ее в этом списке, вы получите 1. Остальные три индекса имеют значение по умолчанию, равное нулю, и не являются частью вашего списка, они являются частью базового массива. Они не актуальны. Если вы попытались сделать myList[3]
, вы все равно получите исключение, оно не просто вернет это значение 0.
Чтобы вернуться к исходному вопросу, в обоих случаях Distinct
возвращает и IEnumberable<int>
с одним элементом. Когда вы вызываете ToList
, он выделяет новый список, счетчик равен 1, базовая структура данных - int[]
с начальной длиной 4. Если вы добавите больше элементов, он будет расти. Во втором примере вы вызываете ToArray
, поэтому он назначает новый int[1]
и возвращает ссылку на него.