【问题标题】:What happens if I initialize an array to size 0?如果我将数组初始化为 0,会发生什么?
【发布时间】:2010-06-23 14:08:25
【问题描述】:

假设我有一个类似的函数:

void myFunc(List<AClass> theList)
{
   string[] stuff = new string[theList.Count];
}

然后我传入一个空列表。

stuff 会是一个空指针吗?还是指向内存中某个未初始化的随机位置的指针?

【问题讨论】:

  • 当你需要一个空的 IEnumerable(通常用于测试)时非常有用
  • Enumerable.Empty&lt;...&gt; 更好。

标签: c# arrays


【解决方案1】:

它将创建一个空数组对象。这仍然是一个完全有效的对象 - 并且占用了非零内存空间。它仍然会知道自己的类型和计数 - 它只是没有任何元素。

空数组通常可用作不可变的空集合:您可以无限地重复使用它们;数组本质上是可变的,但仅限于它们的元素...这里我们没有要更改的元素!由于数组不可调整大小,因此空数组与 .NET 中的对象一样不可变。

请注意,使用空数组而不是空引用通常很有用:返回集合的方法或属性应该几乎总是返回空集合而不是空引用,因为它提供了一致性和统一性- 而不是让每个调用者检查无效。如果您想避免多次分配,可以使用:

public static class Arrays<T>
{
    private static readonly T[] empty = new T[0];

    public static readonly T[] Empty { get { return empty; } }
}

然后你可以使用:

return Arrays<string>.Empty;

(或其他)当您需要使用对特定类型的空数组的引用时。

【讨论】:

  • 我困惑的关键点是空数组是否占用非零空间,正如你所说的那样。
  • 由于有关其“空”的信息必须存储在某个地方(即计数),因此它必须占用一些空间。鉴于我在回答中写的内容,您当然可以(但这很危险)拥有内部指导方针,而不是初始化长度为 0 的数组,而是将引用设置为 null。但是当使用这样的数组时,这可能需要一些额外的检查,不值得节省空间。
  • @NETscape:如果你正在实现一个返回 int[] 的方法并且你没有任何要返回的元素,你会怎么做?
  • @NETscape:返回 null 对所有调用者来说都是一种痛苦。返回一个空数组会提供更加一致、统一的体验。您始终可以存储对空数组的引用,以避免每次需要返回一个时分配它....
  • @Pac0:如果您可以使用Array.Empty,请使用它而不是此答案中的任何代码。但它在 2010 年并不存在 :)
【解决方案2】:

为什么要这样做?它只会指向一个大小为 0 的数组,这是完全有效的。

我认为这里的混淆来自于通过大小为 0 的数组或设置为 null 的变量来表示缺少数据的模糊性(对于空字符串或字符串引用设置为 null 的字符串也存在同样的模糊性) .两者都是表明这种缺席的有效方法,可以说只有一个更有意义。因此,在某些数据库(特别是 Oracle)上,一个空字符串等于 NULL 值,反之亦然,并且一些编程语言(我认为,C# 的新版本就是其中之一)允许指定永远不会为空的引用,也消除了所说的歧义。

【讨论】:

  • "两者都表示数据的缺失,并且没有正确或错误的方式来表示这种缺失。"但从概念上讲,两者之间通常存在差异。这就像有一个空纸板箱和根本没有一个盒子之间的区别。 (我希望我永远不必使用 "" == NULL 的数据库,因为我会对此感到非常困惑。)
  • Oracle 显然可以。我也不是 100% 同意这一点,因为三元逻辑(IS NULL vs = NULL)。
  • NULL == "" 是一个邪恶的 Oracle“特性”——没有健全的系统通常应该将它们平等对待。我的意见...^^
  • 在数据库中,NULL一般表示“这个值是未知的”。所以MIDDLE_NAME IS NULL 表示中间名未知,而MIDDLE_NAME = '' 表示已知此人没有中间名。在 C# 中,null 的语义要广泛得多(不适用、尚未设置等),但空字符串和数组将表明——无论如何对我来说——该值已被确定为空。 (有时在数据库中 NULL 表示“不适用”,但这会激怒核心 RDBMS 理论家。谨慎使用。)
  • @JeffreyLWhitledge 在 Oracle 中,'' IS NULL 为真。所以要小心你所说的一般数据库......
【解决方案3】:

这是很好的代码。您将获得一个 Array 对象,其中包含零项(分配)。

【讨论】:

    【解决方案4】:

    stuff 将引用一个长度为theList.Count 的数组,其中所有条目都初始化为default(string),即null

    【讨论】:

    • 他的意思是你传递一个空列表给它,即 theList.Count 为 0。这当然意味着不会有任何条目初始化任何东西。
    • 在这种情况下,它将是对长度为 0 的数组的引用,其中所有 0 条目都初始化为 null。 ;)
    【解决方案5】:

    以下是 C# 语言规范:

    • 尺寸长度的计算值被验证为 跟随。如果一个或多个值 小于零,a System.OverflowException 被抛出并且 不再执行任何步骤。
    • 分配了具有给定维度长度的数组实例。如果 没有足够的可用内存 分配新实例,a 抛出 System.OutOfMemoryException 并且不执行进一步的步骤。

    所以对于零长度,分配内存。

    【讨论】:

      【解决方案6】:

      如果任何参数为空,Linq .Concat 将抛出异常(在我的情况下可能发生)。所以我不得不在我的代码中做这样的事情:

      public string[] ConcatUsers(string[] users1, string[] users2)
      {
          return (users1 ?? new string[0]).Concat(users2 ?? new string[0]).ToArray();
      }
      

      (只是 0 大小数组初始化器可能有用的示例)

      【讨论】:

        【解决方案7】:

        如果theList 是一个实际的List 对象,并且只是空的,那么theList.Count 将返回0。这意味着声明变为

        string[] stuff = new string[0];
        

        换句话说,stuff 将只是一个长度为 0 的(字符串)数组。

        【讨论】:

        • 不,stuff 将是一个空字符串数组,而不是一个空字符串。
        • 我很确定东西是字符串数组,而不是字符串!?
        • @Eric:我知道,我把stringchar 混为一谈,并且用C/C++ 术语思考(思考太快一直是我的失败之一)。在我看到您的评论之前更正了我的答案。
        【解决方案8】:

        只要您确保您实际传递给该方法的 List 已在某处初始化,例如

        List<Stuff> myStuff = new List<Stuff>;
        

        列表不会指向空值。这将是零个 Stuffs 的列表。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-04
          • 1970-01-01
          相关资源
          最近更新 更多