2010-05-09 56 views
10

如何在1而不是0時在ArrayList中啓動索引?有沒有辦法直接在代碼中做到這一點?如何創建一個起始索引爲1(而不是0)的ArrayList

(請注意,我要求ArrayList,對於普通陣列請參閱Initializing an array on arbitrary starting index in c#

+14

你爲什麼要? – Eric 2010-05-09 20:39:46

+0

@Eric我說爲什麼,在我們大學的第一年,學生參加Pascal和這裏的索引從1開始,所以他們問他們是否可以做C#(只是一個問題)同樣的事情。 – 2010-05-09 20:44:44

+0

0.5呢? :) – 2010-05-09 20:45:54

回答

17

最明顯的方式做這將是包裹在自己實現一個ArrayList,並從所有操作索引減1使用該索引。

你實際上也可以在.NET中聲明一個數組,它有一個arbitrary lower bound(向下滾動到「使用非零下限創建數組」一節)。

這樣說的話,請不要在生產代碼中做。重要的是保持一致。

1
Stuff getValueAtOneBasedIndex(ArrayList<Stuff> list, index) { 
    return list.get(index -1); 
} 
4

嗯,你可以讓你自己:

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); 
    } 
} 

但它引出了一個問題:爲什麼在地球上,你會這麼做呢?

1

正如其他答案所暗示的,有許多方法可以模擬這種情況,但沒有直接的方法可以在C#或其他常用的.NET語言中執行此操作。引用Eric Gunnerson

的CLR不支持這種 結構的(我沒有使用 術語「滑稽」這裏...很難),但 有沒有,據我所知,任何 語言有內置語法到 這樣做。

2

我不知道它是否仍然存在,但是在某一時刻,Visual Basic會允許您使用Option Base 1開始數組索引1。

在C#中,沒有一個System.Collections集合支持這一點,但您可以隨時編寫一個包裝類來爲您執行索引轉換。

真的,但應該避免這種情況。 VB的Option Base創建了比解決更多的問題,我想象,因爲它打破了假設,並使事情更混亂。

7

這樣做的一個正當理由是編寫單元測試。某些第三方SDK(例如Excel COM互操作)期望您可以使用具有基於一個索引的數組。如果您正在使用這樣的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#數組與硬編碼的初始值。在測試代​​碼中這些缺點都不應該是一個大問題。

+0

我注意到我的評論適用於數組,而不是ArrayLists。哎呀。我希望使用Excel和VTSO的人仍然會發現它很有用,儘管它偏離了原來的問題。 – 2013-12-03 01:28:32

1

這裏是什麼我使用的是現在迅速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); 
     } 
    } 
} 
+0

這太棒了!我正在轉換一些舊的Spectrum Basic遊戲,這是非常寶貴的。 – Shevek 2014-04-10 17:51:04

+0

很高興幫助! :) – Larry 2014-04-11 18:24:50

0

首先,讓我通過解釋我的用例來說明這個答案: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; 

這適用於我現在,因爲我只需要在創建函數中執行此操作。在update/get/delete中,無論如何你都會得到基於Excel的數組。也許,未來的改善將是創建一個Excel範圍工廠,避免了0基於默認的建設都在一起,但這種解決方案只是給了我果嶺上我的測試,所以我感動了!

相關問題