簡體   English   中英

即使使用具有容量的構造函數,列表C#的容量始終為0。

[英]List C# capacity is always 0 even though using a constructor with capacity ?

給出以下簡單的同步代碼:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Mutex
{
    class CalcArrayThreads
    {
        private static System.Threading.Mutex mutex = new System.Threading.Mutex();
        private const int ThreadsNumber = 10;
        private static List<int> list = new List<int>(10);
        public static void SumPartialArray(object index)
        {
            mutex.WaitOne();
            int indexBoxed = (int) index;
            int sum = 0;
            for (int i = indexBoxed; i < indexBoxed + 9; i++)
            {
                sum += i;
            }
             Console.WriteLine(string.Format("Thread : {0} Calculated value : {1}", Thread.CurrentThread.Name, sum));

            // list.Add(sum);
            list[indexBoxed] = sum;
            mutex.ReleaseMutex();        
            // Console.WriteLine(list.Count());
        }
        static void Main(string[] args)
        {
            for (int i = 0; i < ThreadsNumber; i++)
            {
                Thread myThread = new Thread(new ParameterizedThreadStart(SumPartialArray));
                myThread.Name = String.Format("Thread{0}", i + 1);
                myThread.Start(i);
            }
            Console.Read();
        }
    }
}

當我使用該行時:

list[indexBoxed] = sum;

我得到:

未處理的異常:System.ArgumentOutOfRangeException:索引超出范圍。 必須為非負數並且小於集合的大小。

即使列表的容量為10。

為什么呢

如果僅對數組執行以下操作,則可以按預期工作,並設置第二個元素:

int[] list = new int[10];

list[2] = 5;  // second element is 5, no exception thrown

看一下List<T>構造函數,當您傳入一個容量時,它實際上是在使用內部數組來做類似的事情:

this._items = new T[capacity];

因此,當您嘗試訪問小於容量的任何元素時,它似乎應該可以工作,但是這是實現索引器的方式:

public T this[int index]
{
    get
    {
        if (index >= this._size)
            throw new ArgumentOutOfRangeException("...");
        return this._items[index];
    }
    set
    {
        if (index >= this._size)
            throw new ArgumentOutOfRangeException("...");
        this._items[index] = value;
    }
}

實際上,它實際上是先檢查_size變量,如果所請求的index大於它,則拋出異常。 如果不是要檢查,它將按您期望的那樣工作。

除非將非空集合傳遞到構造函數中,否則_size初始化為0,並且在使用AddRemoveAtClear等方法時會更改_size 在內部,它仍然只是使用數組來存儲元素,並且如果_size大於容量(例如,嘗試再Add一個元素之后),它將分配一個新數組並復制舊(較小)數組中的所有元素進去。

我看到您可以考慮使用的兩種解決方案:

要么只使用一個數組,像這樣:

private static int[] list = new int[10];

或通過構造函數提供一些默認值的集合(此處為一堆零):

private static List<int> list = new List<int>(Enumerable.Repeat(0, 10));

由於您尚未將任何內容添加到列表中。 它將始終為0

實際上,您實際上需要使用Count屬性來獲取列表中的元素數。

來自MSDN的評論:

容量是列表中需要調整大小之前可以存儲的元素數,而計數是列表中實際存在的元素數。

容量始終大於或等於Count 如果在添加元素時Count超過了Capacity,則通過在復制舊元素和添加新元素之前自動重新分配內部數組來增加容量。

您在構造函數中傳遞的值是初始容量,然后隨着列表的增長而動態增加。

但是列表仍然為空。 並且在空列表上使用索引訪問器將產生您所看到的確切異常。

要將元素添加到列表中,請使用Add方法,而不必擔心容量。 它在內部生長。

編輯:關於您的問題的標題,我相信計數始終為0(您沒有向其中添加元素),而不是容量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM