C# 如何创建起始索引为1(而不是0)的ArrayList

C# 如何创建起始索引为1(而不是0)的ArrayList,c#,java,arraylist,C#,Java,Arraylist,如何在ArrayList中以1而不是0开始索引?有没有一种直接在代码中实现的方法 (请注意,我要求的是ArrayList,对于普通数组,请参见)显而易见的方法是在您自己的实现中包装一个ArrayList,并在使用索引的所有操作中从索引器中减去1 实际上,您还可以在.NET中声明一个数组,该数组具有一个(向下滚动到“创建具有非零下限的数组”一节) 话虽如此,请不要在生产代码中这样做。保持一致性很重要。Stuff getValueAtOneBasedIndex(ArrayList,index){ S

如何在
ArrayList
中以1而不是0开始索引?有没有一种直接在代码中实现的方法


(请注意,我要求的是
ArrayList
,对于普通数组,请参见)

显而易见的方法是在您自己的实现中包装一个ArrayList,并在使用索引的所有操作中从索引器中减去1

实际上,您还可以在.NET中声明一个数组,该数组具有一个(向下滚动到“创建具有非零下限的数组”一节)

话虽如此,请不要在生产代码中这样做。保持一致性很重要。

Stuff getValueAtOneBasedIndex(ArrayList,index){
Stuff getValueAtOneBasedIndex(ArrayList<Stuff> list, index) {
     return list.get(index -1);
}
返回列表.get(索引-1); }
好吧,你可以自己做:

public class MyArrayList<T> extends ArrayList<T> {
    public T get(int index) {
        super.get(index - 1);
    }

    public void set(int index, T value) {
        super.set(index - 1, value);
    }
}
公共类MyArrayList扩展了ArrayList{
公共T获取(整数索引){
super.get(索引-1);
}
公共无效集(整数索引,T值){
super.set(索引-1,值);
}
}

但它回避了一个问题:你到底为什么要费心呢?

正如其他答案所表明的那样,有一些方法可以模拟这种情况,但在C#或其他常用的.NET语言中没有直接的方法。引述:

CLR确实支持这种类型的 构造(我很难不使用 这里的“滑稽”一词…,但是 据我所知,没有 具有内置语法的语言 那样做


我不知道它是否仍然存在,但在某一点上,VisualBasic会让您从1开始使用数组索引

在C#中,System.Collections都不支持这一点,但是您可以编写一个包装器类来为您进行索引转换


但实际上,这是应该避免的。VB的
选项库
产生的问题比它解决的问题要多,我想这是因为它打破了假设,使事情变得更加混乱。

这样做的一个合理原因是编写单元测试。某些第三方SDK(例如Excel COM interop)希望您使用具有基于索引的数组。如果您正在使用这样的SDK,那么您可以而且应该在C#测试框架中删除此功能

以下方面应起作用:

object[,] comInteropArray = Array.CreateInstance(
    typeof(object),
    new int[] { 3, 5 },
    new int[] { 1, 1 }) as object[,];

System.Diagnostics.Debug.Assert(
     1 == comInteropArray.GetLowerBound(0),
    "Does it look like a COM interop array?");
System.Diagnostics.Debug.Assert(
     1 == comInteropArray.GetLowerBound(1),
    "Does it still look like a COM interop array?");

我不知道是否有可能将其转换为标准的C#风格数组。可能不会。我也不知道用什么干净的方法来硬编码这样一个数组的初始值,除了用硬编码的初始值从标准C#数组中循环复制它们。这两个缺点在测试代码中都不是什么大问题。

下面是我现在正在使用的一个工具,用于将VBA应用程序快速移植到C#:

它是一个数组类,以1开头并接受多个维度

虽然还有一些额外的工作要做(IEnumerator等),但这只是一个开始,对我来说已经足够了,因为我只使用索引器

public class OneBasedArray<T>
{
    Array innerArray;

    public OneBasedArray(params int[] lengths)
    {
        innerArray = Array.CreateInstance(typeof(T), lengths, Enumerable.Repeat<int>(1, lengths.Length).ToArray());
    }

    public T this[params int[] i]
    {
        get
        {
            return (T)innerArray.GetValue(i);
        }
        set
        {
            innerArray.SetValue(value, i);
        }
    }
}
公共类OneBasedArray
{
数组内部数组;
公共OneBasedArray(参数int[]长度)
{
innerArray=Array.CreateInstance(typeof(T),Length,Enumerable.Repeat(1,Length.Length.ToArray());
}
公共T此[params int[]i]
{
得到
{
return(T)innerArray.GetValue(i);
}
设置
{
SetValue(值,i);
}
}
}

首先,让我在回答这个问题之前先解释一下我的用例:Excel Interop。使用数组读写数据容易得多,但Excel Range.Value2神奇地返回了一个基于1的对象数组

因此,如果你正在向Excel写信,而这正是你首先提出这个问题的原因。。。然后也许停止与c#的斗争,让Excel为您实例化数组。因此,不是:

object[,] newArray = new object[indexR, indexC];
您可以使用:

object[,] newArray = (object[,])RangeToWriteTo.Value2;
在我的例子中,我创建了一个包装器类,允许我对如下属性使用数组:

public abstract class ExcelRowBase
    {
        public object[,] data;

        public ExcelRowBase(int index)
        {
            data = new object[2, index + 1];
        }
    }

 public class InstanceRowModel : ExcelRowBase 
    {
        public InstanceRowModel() : base(8) 
        { 
        //constructor unique to Wire Table 
        }

        public object Configuration
        {
            get
            {
                return data[1, 1];
            }
            set
            {
                data[1, 1] = value;
            }
        }
...
所以在所有情况下,我都是从同一个索引中读取的。因此,要将传递的模型转换为Create方法,只需将属性复制到使用从Excel创建的数组的模型中

            insertingModel.data = (object[,])writeRange.Value2;

            //manually copying values from one array to the other
            insertingModel.Configuration = model.Configuration;
            ...

            writeRange.Value2 = insertingModel.data;

这对我现在来说是可行的,因为我只需要在create函数中执行。在update/get/delete中,您将获得基于Excel的数组。也许未来的改进是创建一个Excel范围工厂,避免所有基于0的默认构造,但是这个解决方案在我的测试中给了我绿色,所以我继续

你为什么要这样做?@Eric我会说为什么,在我们大学的第一年,学生们学习Pascal,这里的索引从1开始,所以他们问他们是否可以用c#做同样的事情(只是一个问题)。不使用
ArrayList
怎么样?至少在.NET中,从5年前开始,它就被通用集合所取代。当你学习西班牙语时,你不会问“有没有办法说英语,让他们明白我的意思?”。计算机语言也是如此。当你“说”一门计算机语言时,你必须使用它的词汇表。C#的数组以0开头。如果您想从1开始,请编写Pascal。我目前有一个业务需求,就是将工程师编写的计算代码移植到VBA Excel中,并将其集成到我们的自动化服务体系结构(C#)中。工程师对计算了解很多,而对编程了解较少。他已经尽了最大的努力,并且在他的线性方程组算法中密集地使用了数组。因为必须这样做,我没有时间浪费重写所有的数组逻辑,现在我有一个很好的理由,在C#中使用以1开头的特殊数组。这可以干净地完成,并且有很好的文档记录。谢谢你的提问。我注意到我的评论适用于数组,而不是ArrayList。哎呀。我希望使用Excel和VTSO的人仍然会发现它有用,即使它偏离了最初的问题。这太棒了!我正在转换一些旧的频谱基本游戏,这是无价的。