如何以及何时放弃在C#中使用数组?

如何以及何时放弃在C#中使用数组?,c#,.net,arrays,theory,C#,.net,Arrays,Theory,我一直被告知向数组中添加元素的过程如下: 数组+1元素的空副本无效 创建,然后从 然后将原始数组复制到其中 新元素的新数据为 然后加载 如果这是真的,那么由于内存和CPU利用率的原因,禁止在需要大量元素活动的场景中使用数组,对吗 如果是这样的话,在添加大量元素时,是否应该尽量避免使用数组?你应该改用iStringMap吗?如果是这样的话,如果您需要两个以上的维度,并且需要添加大量的元素添加,会发生什么情况。您只是受到性能的影响,还是应该使用其他内容?调整阵列大小时,必须分配新阵列,并复制内容。如

我一直被告知向数组中添加元素的过程如下:

数组+1元素的空副本无效 创建,然后从 然后将原始数组复制到其中 新元素的新数据为 然后加载

如果这是真的,那么由于内存和CPU利用率的原因,禁止在需要大量元素活动的场景中使用数组,对吗


如果是这样的话,在添加大量元素时,是否应该尽量避免使用数组?你应该改用iStringMap吗?如果是这样的话,如果您需要两个以上的维度,并且需要添加大量的元素添加,会发生什么情况。您只是受到性能的影响,还是应该使用其他内容?

调整阵列大小时,必须分配新阵列,并复制内容。如果您只是修改数组的内容,那么它只是一个内存分配


因此,当您不知道数组的大小,或者数组的大小可能会改变时,不应该使用数组。但是,如果您有一个固定长度的数组,那么它们是通过索引检索元素的一种简单方法。

请查看通用
列表
,以替换数组。它们支持阵列的大部分功能,包括根据需要分配初始存储大小

你能做的最好的事情就是尽可能提前分配所需的内存。这将避免必须进行额外的调用以获取堆上的内存。如果不能做到这一点,那么以五块或任何对应用程序有意义的数字进行分配是有意义的


这是一条规则,您可以应用于任何实际情况。

标准数组应定义一个长度,该长度在连续块中保留它所需的所有内存。向数组中添加项会将其放入已保留的内存块中。

一般来说,我宁愿避免使用数组。只需使用列表。它在内部使用一个动态大小的数组,对于大多数使用来说速度足够快。如果您使用的是多维数组,请在必要时使用列表。就内存而言,这并没有那么糟糕,而且添加项要简单得多


如果您的使用率为0.1%,需要极高的速度,请在尝试优化它之前,确保列表访问是真正的问题。

ArrayList and list在需要时将数组增加一倍以上(我认为是通过将大小加倍,但我没有检查源代码)。在构建动态大小的阵列时,它们通常是最佳选择


当基准测试表明数组大小调整严重降低了应用程序的速度时(请记住,过早优化是万恶之源),您可以评估编写具有调整大小行为的自定义数组类。

数组对于少量写入和多次读取都很好,特别是对于迭代性质的写入和读取,对于其他任何操作都是如此,使用许多其他数据结构中的一种。

如果要大量添加/删除元素,只需使用列表即可。如果它是多维的,你可以使用列表或其他东西

另一方面,如果您主要做的是遍历列表,则列表的效率低于数组,因为数组都位于CPU缓存中的一个位置,列表中的对象分散在该位置

如果要使用数组进行高效读取,但要经常“添加”元素,则有两个主要选项:

1) 将其生成为列表(或列表列表),然后使用ToArray()将其转换为有效的数组结构


2) 将数组分配为大于所需的大小,然后将对象放入预先分配的单元格中。如果最终需要的元素比预先分配的还要多,则可以在阵列填充时重新分配,每次将大小增加一倍。这将提供O(logn)大小调整性能,而不是O(n),就像每个添加阵列重新分配一次一样。请注意,这就是StringBuilder的工作原理,它为您提供了一种快速的方式来不断追加字符串。

您是对的,数组非常适合查找。但是,对阵列大小的修改代价高昂

在修改阵列大小的场景中,应该使用支持增量大小调整的容器。您可以使用允许您设置初始大小的ArrayList,并且您可以不断检查大小与容量,然后将容量增加一大块以限制大小调整的数量


或者你可以使用一个链表。然而,查找很慢…

这实际上取决于“添加”的含义

如果你的意思是:

T[] array;
int i;
T value;
...
if (i >= 0 && i <= array.Length)
    array[i] = value;
T[]数组;
int i;
T值;
...

如果(i>=0&&i如果我认为我将在集合的生命周期内向集合中添加很多项,那么我将使用列表。如果我确定声明集合时集合的大小,那么我将使用数组


我通常在列表上使用数组的另一种情况是,当我需要将集合作为对象的属性返回时-我不希望调用方通过列表的Add方法添加集合中的项,而是希望调用方通过我的对象接口将项添加到集合中。在这种情况下,我将获取内部列表并调用ToArray并返回array。

通常,如果您必须具有最佳的索引查找性能,最好先构建一个列表,然后将其转换为一个数组,这样一开始只需支付少量的罚款,但避免以后再使用。如果问题是您将不断添加新数据并删除旧数据,那么为了方便起见,您可能需要使用ArrayList或List,但请保留请记住,它们只是特例数组。当它们“增长”时,它们会分配一个全新的数组,并将所有内容复制到其中,这非常缓慢

只是一个阵列,需要时会增长。 Add是按O(1)摊销的,只是要小心确保
string[] strings = ...
object[] objects = strings;
objects[0] = 1; //compiles, but gives a runtime exception.
struct Value { public int mutable; }

var array = new[] { new Value() };  
array[0].mutable = 1; //<-- compiles !
//a List<Value>[0].mutable = 1; doesnt compile since editing a copy makes no sense
print array[0].mutable // 1, expected or unexpected? confusing surely
public class Class : IEquatable<Class>
{
    public bool Equals(Class other)
    {
        Console.WriteLine("generic");
        return true;
    }
    public override bool Equals(object obj)
    {
        Console.WriteLine("non generic");
        return true;
    } 
}

public struct Struct : IEquatable<Struct>
{
    public bool Equals(Struct other)
    {
        Console.WriteLine("generic");
        return true;
    }
    public override bool Equals(object obj)
    {
        Console.WriteLine("non generic");
        return true;
    } 
}

class[].Contains(test); //prints "non generic"
struct[].Contains(test); //prints "generic"
Expression<Func<string>> e = () => new[] { "a" }[0];
//e.Body.NodeType == ExpressionType.ArrayIndex

Expression<Func<string>> e = () => new List<string>() { "a" }[0];
//e.Body.NodeType == ExpressionType.Call;
public ReadOnlyCollection<T> ToReadOnlyCollection<T>(IEnumerable<T> source)
{
    return source.ToList().AsReadOnly();
}