Список показывает 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] и возвращает ссылку на него.