对于多维数组,Array.CreateInstance可用于创建基于非零索引的数组,但如果您尝试使用1维数组(向量),例如:
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”
,我会接受There's no obvious way to make a non-zero-based array in C#的话。答案 0 :(得分:25)
你可以在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语法比在每次出现时从向量索引中减去一个语法更加丑陋。
如果值类型存储在数组中,那么它将被存储在连续位置,就像在常规数组中一样,但是getter和setter将需要装箱值(除非有一些编译器魔法我不是意识到)。吸气剂通常需要一个演员(只是为了使它更加丑陋)。
double myValue = (double)myArray.GetValue(index);
另请注意,GetUpperBound
的正确比较为<=
,与Length
的{{1}}不同。
答案 1 :(得分:12)
基于非零的数组DO存在于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);
}
在这种情况下,这个代码是必要的原因是每个DCOM调用excel都是一个跨进程调用,如果你要一次一个地访问单元格,你会产生巨大的开销,(或者检索或设置值)。 Excel范围是基于1的2维数组,如果创建数组并在本地填充数组,则可以将其推送到一个跨进程调用中,从而产生巨大的性能提升。
答案 2 :(得分:0)
如果有人仍在寻找基于一的数组的实现,那么这里是一维通用基于一的数组,它只是常规数组的包装类型:
还有一个二维版本,但到目前为止还没有更高版本(此代码是为支持Excel而编写的,因此只需要2D):
这两种类型的测试都在同一个仓库下的相关测试项目中为它们编写:
https://github.com/ColmBhandal/CsharpExtras/tree/master/CsharpExtrasTest/OneBased
免责声明:这些存储库托管在我的个人GitHub帐户上,并且是开源的。
答案 3 :(得分:-4)
C#中的所有数组都是基于零的。据我所知,没有办法创建一个基于1的数组。想象一下,如果可能的话会发生什么样的混乱。这是一个类似的主题,它通过更多细节解释了这个问题 - C#: Nonzero-based arrays are not CLS-compliant