【问题标题】:C# equivalent to Delphi High() and Low() functions for arrays that maintains performance?对于保持性能的数组,C# 相当于 Delphi High() 和 Low() 函数?
【发布时间】:2013-03-14 05:10:00
【问题描述】:

在 Delphi 中有 Low() 和 High() 函数,它们返回数组的最低和最高索引维度。这有助于消除容易出错的 for 循环,因为迭代数组可能会成为潜在的 +1/-1 数组边界错误的牺牲品,例如在您的意思是 时使用 > 用于 for 循环 语句中的终止条件。

下面是 Low/High 函数的示例(在 Delphi 中):

for i := Low(ary) to High(ary) do

现在我在 C# 中使用一个简单的 for 循环 语句:

for (int i = 0; i < ary.Length; i++)

我知道有 Array 方法 GetDimension(N) 但它有其自身的责任,因为我可能会因不小心使用错误的维度索引而引入错误。我想我可以用枚举器做一些事情,但我担心与使用 for 循环 相比,扫描大型数组时会产生显着的性能成本。 C# 中是否有等效于 High/Low 的方法?

【问题讨论】:

    标签: c# arrays delphi iteration dimensions


    【解决方案1】:

    与内部low(ary)high(ary) 函数等效的C# 分别是0ary.Length-1。那是因为C# arrays are zero based。我看不出为什么数组的 Length 属性应该具有与 Delphi 的 high() 不同的性能特征。

    在性能方面,Pascal for 循环与 C 派生语言使用的循环之间的最大区别在于终止测试的评估。考虑一个经典的 Pascal for 循环:

    for i := 0 to GetCount()-1 do
      ....
    

    对于 Pascal for 循环,GetCount() 仅在循环开始时计算一次。

    现在考虑 C 派生语言中的等价物:

    for (int i=0; i<GetCount(); i++)
      ....
    

    在这个循环中,GetCount() 每次循环都会被评估。因此,在像 C# 这样的语言中,您需要一个局部变量来避免一遍又一遍地调用该函数。

    int N = GetCount();
    for (int i=0; i<N; i++)
      ....
    

    在数组的情况下,如果优化器可以确定ary.Length 在循环期间没有发生变异,那么编译器可以优化代码。我个人不知道 C# 优化器是否这样做,但请参阅 cmets 了解更多信息。

    在开始重写循环以使用包含数组长度的局部变量之前,请检查它是否有任何区别。几乎可以肯定它不会。我在上面概述的 Pascal 和 C 类 for 循环之间的区别可能在语义方面比在性能方面更重要。


    我特别羡慕的语言是D。这里可以使用foreach循环,将数组中的每一项呈现为引用,从而可以修改数组的内容:

    void IncArray(int[] array, int increment) {
        foreach (ref e; array) {
            e += increment;
        }
    }    
    

    【讨论】:

    • 我之前发布的表达式在调试 C# 代码时在调试器即时窗口中工作,但如果你在编译 C# 源代码中尝试它会抛出 InvalidCastException... 有趣
    • @280Z28 这是一个有趣的好奇心,我同意。但这里可能跑题了。
    • 如果在 C# 中允许,那么您绝对可以创建一个不使用 [0, Length) 作为边界的数组。您仍然可以在 C# 中创建这样的数组,但它的类型将是 IList&lt;byte&gt; 而不是 byte[]
    • 是的。我为 C# 数组添加了指向 MSDN 文档的链接,以防止您的 cmets! ;-)
    • 只有当arr 是一个局部变量时,.NET 优化器才会优化for (int i = 0; i &lt; arr.Length; i++)。如果是字段,则无法进行优化(因为另一种方法可能会将arr更改为指向不同的数组对象)。
    【解决方案2】:

    在 C# 中,下边界始终为零,因此 Low(ary) 的等价物就是 0

    对于一维数组,High(ary) 的等价物是ary.Length - 1。 (对于多维数组,你需要不止一个循环。)

    【讨论】:

      【解决方案3】:

      你能改用foreach 语句吗? 喜欢

      foreach(int i in ary)
      {
      . . .
      }
      

      【讨论】:

      • 我经常要修改数组的元素,而foreach语句的迭代变量是不可变的。
      • @RobertOschler 可能应该在问题中说明。
      【解决方案4】:

      [边界(int Dimension)]

      这些边界函数为任何数组的用户指定维度提供起点和终点。第二个维度会用 1 来标注,而不是 0,依此类推。

      for (int i = ary.GetLowerBound(0); i <= ary.GetUpperBound(0); i++ )
      {}
      

      【讨论】:

      • 你确定你的代码sn-p够用吗?看看其他答案 - 他们都有很好的解释部分,而你的答案质量很低。
      • 答案很简短,解释可能很好,但问题是Is there an equivalent to High/Low in C#?。他们已经提供了。
      • 有时少即是多,有时一点点试错工作会让一个人成为更好的程序员。
      最近更新 更多