如何在c#中创建一个索引从1开始的一维数组

本文关键字:索引 一个 开始 一维数组 创建 | 更新日期: 2023-09-27 17:52:17

用于多维数组。CreateInstance可以用来创建基于索引的非零数组,但是如果你尝试创建一维数组(向量),例如:

public double[] myArray = (double[])Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });

当从多维数组强制转换为单维数组失败时,这将在运行时失败

"Unable to cast object of type 'System.Double[*]' to type 'System.Double[]'"

现在我可以创建一个零基数组并忽略第一个值,或者使用偏移量等,但我是否忽略了一些c#语法魔法,允许非零基向量?

更新:

我相信Eric Lippert的话,如果他说"在c#中没有明显的方法来创建非从零开始的数组"

如何在c#中创建一个索引从1开始的一维数组

您可以在c#中创建非从零开始的数组,但是使用它有点令人讨厌。它绝对不是普通数组(即从零开始的一维数组)的简单替代品。

        // Create the array.
        Array myArray = Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });
        // Fill the array with random values.
        Random rand = new Random();
        for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
        {
            myArray.SetValue(rand.NextDouble(), index);
        }
        // Display the values.
        for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
        {
            Console.WriteLine("myArray[{0}] = {1}", index, myArray.GetValue(index));
        }

为此所需的GetValue/SetValue语法比每次从vector索引中减去1更难看。

如果值类型存储在数组中,那么它将像在常规数组中一样存储在连续位置,但是getter和setter将需要将值装箱(除非有一些我不知道的编译器魔法)。getter通常需要强制类型转换(只是为了让它更难看)。

    double myValue = (double)myArray.GetValue(index);

还注意GetUpperBound的正确比较是<=,不像Length是与<比较。

基于非零的数组确实存在于C中,并且有一种方法可以创建一个基于1的(或任何)数组。

我完全同意它们是混乱的,它们不应该用于除了遗留的东西之外的任何东西,但是它们对于与旧的COM库交互是必不可少的。

最常见的情况是使用Excel库中的Microsoft.Office.Interop.Excel.Range对象,该对象仍然使用旧的DCOM接口。

的例子:

/// <summary>
    /// Makes the equivalent of a local Excel range that can be populated 
    ///  without leaving .net
    /// </summary>
    /// <param name="iRows">number of rows in the table</param>
    /// <param name="iCols">number of columns in the table</param>
    /// <returns>a 1's based, 2 dimensional object array which can put back to Excel in one DCOM call.</returns>
    public static object[,] NewObjectArray(int iRows, int iCols)
    {
        int[] aiLowerBounds = new int[] { 1, 1 };
        int[] aiLengths = new int[] { iRows, iCols};
        return (object[,])Array.CreateInstance(typeof(object), aiLengths, aiLowerBounds);
    }

在本例中,需要此代码的原因是对excel的每个DCOM调用都是一个跨进程调用,如果要一次访问一个单元格,则会产生巨大的开销(检索或设置值)。Excel范围是一个基于1的二维数组,如果创建了这个数组,并在本地填充它,它可以在一个跨进程调用中被推送到Excel中,从而产生巨大的性能改进。

如果有人还在寻找一个基于一维的数组实现,这里是一个一维通用的基于一维的数组,它只是一个常规数组的包装类型:

https://github.com/ColmBhandal/CsharpExtras/blob/master/CsharpExtras/Enumerable/OneBased/OneBasedArray.cs

也有一个二维版本,但还没有更高维度的版本(这段代码是为了支持Excel而写的,所以2D就足够了):

https://github.com/ColmBhandal/CsharpExtras/blob/master/CsharpExtras/Enumerable/OneBased/OneBasedArray2D.cs

这两种类型都在相同的repo下的相关测试项目中为它们编写了测试:

https://github.com/ColmBhandal/CsharpExtras/tree/master/CsharpExtrasTest/OneBased

免责声明:这些repos托管在我的个人GitHub帐户上,并且是开源的。

c#中的所有数组都是从零开始的。据我所知,没有办法创建一个基于1的数组。想象一下,如果这是可能的,会发生什么样的混乱。下面是一个类似的线程,它更详细地解释了这个问题——c#:非基于零的数组不符合cls