给出这个简单的同步代码:
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。
为什么?
答案 0 :(得分:2)
由于您尚未向列表中添加任何内容。它始终是0
。
您实际上需要使用Count
属性来获取列表中的元素数量。
来自MSDN的评论:
容量是List之前可以存储的元素数 需要调整大小,而Count是元素的数量 实际上在列表中。
容量始终大于或等于计数。如果计数超过 添加元素时的容量,容量增加了 在复制旧数据之前自动重新分配内部数组 元素和添加新元素。
答案 1 :(得分:2)
如果您只是使用数组执行以下操作,它将按预期工作,设置第二个元素:
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,除非您将非空集合传递给构造函数,并在使用Add
,RemoveAt
,Clear
等时更改值方法。在内部,它仍然只是使用数组来存储元素,如果_size
大于容量(比如,在尝试Add
一个元素之后),它会分配一个新数组并将旧(较小)数组中的所有元素复制到其中。
我看到了您可以考虑使用的两种解决方案:
要么只使用一个数组,就像这样:
private static int[] list = new int[10];
或者通过构造函数提供一些默认值的集合(这里是一堆零):
private static List<int> list = new List<int>(Enumerable.Repeat(0, 10));
答案 2 :(得分:0)
您在构造函数中传递的值是初始容量,然后随着列表的增长动态增加。
但是清单仍然是空的。在空列表中使用索引访问器将产生您所看到的确切异常。
要向列表添加元素,请使用Add方法,而不要担心容量。它在内部发展。
编辑:关于你问题的标题,我相信Count总是0(你没有添加元素)而不是容量。