C# .NET 中的空数组是否使用任何空间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/151936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:47:10  来源:igfitidea点击:

Does an empty array in .NET use any space?

提问by Orion Edwards

I have some code where I'm returning an array of objects.

我有一些代码,用于返回一组对象。

Here's a simplified example:

这是一个简化的示例:

string[] GetTheStuff() {
    List<string> s = null;
    if( somePredicate() ) {
        s = new List<string>(); // imagine we load some data or something
    }
    return (s == null) ? 
        new string[0] :
        s.ToArray();
}

The question is, how expensive is the new string[0]?
Should I just return null and make the caller accept null as a valid way of indicating "nothing was found"?

问题是,到底有多贵new string[0]
我是否应该只返回 null 并让调用者接受 null 作为指示“未找到任何内容”的有效方式?

NB: This is being called in a loop which gets run hundreds and hundreds of times, so it's one of the few cases where I think this kind of optimiziation is not actually 'premature'.

注意:这是在一个循环中调用的,该循环会运行成百上千次,因此这是我认为这种优化实际上并不“过早”的少数情况之一。

PS: And even if it was premature, I'd still like to know how it works :-)

PS:即使为时过早,我仍然想知道它是如何工作的:-)

Update:

更新:

Initially when I asked if it used any space, I was thinking of things from the 'C/C++' point of view, kind of like how in C, writing char a[5];will allocate 5 bytes of space on the stack, and char b[0];will allocate 0 bytes.

最初,当我问它是否使用任何空间时,我是从“C/C++”的角度考虑的,有点像在 C 中,写入char a[5];将在堆栈上分配 5 个字节的空间,char b[0];并将分配 0 个字节。

I realise this is not a good fit for the .NET world, but I was curious if this was something that the compiler or CLR would detect and optimize out, as a non-resizeable array of size zero really shouldn't (as far as I can see?) require any storage space.

我意识到这不太适合 .NET 世界,但我很好奇编译器或 CLR 是否会检测并优化出这种情况,因为大小为零的不可调整大小的数组真的不应该(就我可以看到?)需要任何存储空间。

采纳答案by Jon Skeet

Even if it's being called "hundreds and hundreds" of times, I'd say it's a premature optimization. If the result is clearer as an empty array, use that.

即使它被称为“成百上千次”,我也会说这是一个过早的优化。如果结果作为空数组更清晰,请使用它。

Now for the actual answer: yes, an empty array takes some memory. It has the normal object overhead (8 bytes on x86, I believe) and 4 bytes for the count. I don't know whether there's anything beyond that, but it's not entirely free. (It isincredibly cheap though...)

现在来看看实际的答案:是的,一个空数组需要一些内存。它具有正常的对象开销(x86 上的 8 个字节,我相信)和 4 个字节的计数。我不知道除此之外是否还有其他东西,但它并非完全免费。(不过价格实在是太便宜了……)

Fortunately, there's an optimization you can make without compromising the API itself: have a "constant" of an empty array. I've made another small change to make the code clearer, if you'll permit...

幸运的是,您可以在不影响 API 本身的情况下进行优化:拥有一个空数组的“常量”。如果你允许的话,我做了另一个小改动以使代码更清晰......

private static readonly string[] EmptyStringArray = new string[0];

string[] GetTheStuff() {
    if( somePredicate() ) {
        List<string> s = new List<string>(); 
        // imagine we load some data or something
        return s.ToArray();
    } else {
        return EmptyStringArray;
    }
}

If you find yourself needing this frequently, you could even create a generic class with a static member to return an empty array of the right type. The way .NET generics work makes this trivial:

如果你发现自己经常需要这个,你甚至可以创建一个带有静态成员的泛型类来返回一个正确类型的空数组。.NET 泛型的工作方式使这变得微不足道:

public static class Arrays<T> {
    public static readonly Empty = new T[0];
}

(You could wrap it in a property, of course.)

(当然,您可以将其包装在属性中。)

Then just use: Arrays<string>.Empty;

然后只需使用: Arrays<string>.Empty;

EDIT: I've just remembered Eric Lippert's post on arrays. Are you sure that an array is the most appropriate type to return?

编辑:我刚刚记得Eric Lippert 在 arrays 上的帖子。您确定数组是最适合返回的类型吗?

回答by Matt Hamilton

I would guess that an empty array uses only the space needed to allocate the object pointer itself.

我猜想一个空数组只使用分配对象指针本身所需的空间。

From memory the API guidelines say that you should always return an empty array from a method that returns an array rather than returning null, so I'd leave your code the way it is regardless. That way the caller knows he's guaranteed to get an array (even an empty one) and need not check for null with each call.

根据记忆,API 指南说您应该始终从返回数组的方法中返回一个空数组,而不是返回 null,因此无论如何我都会保留您的代码。这样调用者就知道他保证得到一个数组(甚至是一个空数组)并且不需要在每次调用时检查 null。

Edit: A link about returning empty arrays:

编辑:关于返回空数组的链接:

http://wesnerm.blogs.com/net_undocumented/2004/02/empty_arrays.html

http://wesnerm.blogs.com/net_undocumented/2004/02/empty_arrays.html

回答by Jon Limjap

Declared arrays will always have to contain the following information:

声明的数组必须始终包含以下信息:

  • Rank (number of dimensions)
  • Type to be contained
  • Length of each dimension
  • 等级(维数)
  • 要包含的类型
  • 每个维度的长度

This would most likely be trivial, but for higher numbers of dimensions and higher lengths it willhave a performance impact on loops.

这很可能是微不足道的,但对维数越来越高的长度也将会对循环性能的影响。

As for return types, I agree that an empty array should be returned instead of null.

至于返回类型,我同意应该返回一个空数组而不是 null。

More information here: Array Types in .NET

此处的更多信息:.NET 中的数组类型

回答by Dr8k

If I understand correctly, a small amount of memory will be allocated for the string arrays. You code essentially requires a generic list to be created anyway, so why not just return that?

如果我理解正确,将为字符串数组分配少量内存。您的代码本质上需要创建一个通用列表,那么为什么不直接返回它呢?

[EDIT]Removed the version of the code that returned a null value. The other answers advising against null return values in this circumstance appear to be the better advice[/EDIT]

[编辑] 删除了返回空值的代码版本。在这种情况下建议不要使用空返回值的其他答案似乎是更好的建议[/编辑]

List<string> GetTheStuff()
{
   List<string> s = new List<string();
   if (somePredicarte())
   {
      // more code
   }
   return s;
}

回答by VVS

This is not a direct answer to your question.

这不是对您问题的直接回答。

Read why arrays are considered somewhat harmful. I would suggest you to return an IList<string> in this case and restructure the code a little bit:

阅读为什么数组被认为有些有害。在这种情况下,我建议您返回一个 IList<string> 并稍微重构代码:

IList<string> GetTheStuff() {
    List<string> s = new List<string>();
    if( somePredicate() ) {
        // imagine we load some data or something
    }
    return s;
}

In this way the caller doesn't have to care about empty return values.

通过这种方式,调用者不必关心空的返回值。



EDIT: If the returned list should not be editable you can wrap the List inside a ReadOnlyCollection. Simply change the last line to. I also would consider this best practice.

编辑:如果返回的列表不应该是可编辑的,您可以将列表包装在ReadOnlyCollection 中。只需将最后一行更改为。我也会考虑这个最佳实践。

    return new ReadOnlyCollection(s);

回答by Greg Beech

Yes, as others have said, the empty array takes up a few bytes for the object header and the length field.

是的,正如其他人所说,空数组占用对象头和长度字段的几个字节。

But if you're worried about performance you're focusing on the wrong branch of execution in this method. I'd be much more concerned about the ToArraycall on the populated list which will result in a memory allocation equal to its internal size and a memory copy of the contents of the list into it.

但是,如果您担心性能,那么您将关注此方法中错误的执行分支。我更关心填充列表上的ToArray调用,这将导致内存分配等于其内部大小,并将列表内容的内存副本复制到其中。

If you really want to improve performance then (if possible) return the list directly by making the return type one of: List<T>, IList<T>, ICollection<T>, IEnumerable<T>depending on what facilities you need from it (note that less specific is better in the general case).

如果您真的想提高性能,那么(如果可能)通过将返回类型设为以下之一来直接返回列表:List<T>, IList<T>, ICollection<T>, IEnumerable<T>取决于您需要从中获取哪些设施(请注意,在一般情况下,越不具体越好)。

回答by Drew Noakes

Others have answered your question nicely. So just a simple point to make...

其他人已经很好地回答了你的问题。所以只是一个简单的点...

I'd avoid returning an array (unless you can't). Stick with IEnumerable and then you can use Enumerable.Empty<T>()from the LINQ APIs. Obviously Microsoft have optimised this scenario for you.

我会避免返回一个数组(除非你不能)。坚持使用 IEnumerable,然后您可以Enumerable.Empty<T>()从 LINQ API 中使用。显然微软已经为你优化了这个场景。

IEnumerable<string> GetTheStuff()
{
    List<string> s = null;
    if (somePredicate())
    {
        var stuff = new List<string>();
        // load data
        return stuff;
    }

    return Enumerable.Empty<string>();
}

回答by Jeppe Stig Nielsen

The upcoming version 4.6 of .NET (later in 2015) contains a static methodreturning a length-zero string[]:

即将发布的 .NET 4.6 版(2015 年晚些时候)包含一个返回长度为零的静态方法string[]

Array.Empty<string>()

I suppose it returns the same instance if called many times.

我想如果多次调用它会返回相同的实例。

回答by Yitzchak

I know this is old question, but it's a basic question and I needed a detailed answer.

我知道这是个老问题,但这是一个基本问题,我需要一个详细的答案。

So I explored this and got results:

所以我探索了这个并得到了结果:

In .Net when you create an array (for this example I use int[]) you take 6 bytesbefore any memory is allocated for your data.

在 .Net 中,当你创建一个数组时(在这个例子中我使用int[]),在为你的数据分配任何内存之前你需要6 个字节

Consider this code [In a 32 bitapplication!]:

考虑以下代码 [在32 位应用程序中!]:

int[] myArray = new int[0];
int[] myArray2 = new int[1];
char[] myArray3 = new char[0];

And look at the memory:

并查看内存:

myArray:  a8 1a 8f 70 00 00 00 00 00 00 00 00
myArray2: a8 1a 8f 70 01 00 00 00 00 00 00 00 00 00 00 00
myArray3: 50 06 8f 70 00 00 00 00 00 00 00 00


Lets explain that memory:

让我们解释一下内存:

  • Looks like the first 2 bytes are some kind of metadata, as you can see it changes between int[]and char[](a8 1a 8f 70vs50 06 8f 70)
  • Then it holds the size of the array in integer variable (little endian). so it's 00 00 00 00for myArrayand 01 00 00 00for myArray2
  • Now it's our precious Data[I tested with Immediate Window]
  • After that we see a constant (00 00 00 00). I don't know what its meaning.
  • 看起来前 2 个字节是某种元数据,你可以看到它在int[]char[]( a8 1a 8f 70vs )之间变化50 06 8f 70
  • 然后它将数组的大小保存在整数变量(小端)中。所以这是00 00 00 00为了myArray01 00 00 00为了myArray2
  • 现在是我们宝贵的数据[我用即时窗口测试]
  • 之后我们看到一个常数 ( 00 00 00 00)。我不知道它是什么意思。


Now I feel a lot better about zero length array, I know how it works=]

现在我对零长度数组感觉好多了,我知道它是如何工作的=]