2010-05-09 34 views
10

Làm cách nào để tôi có thể bắt đầu chỉ mục trong một số ArrayList ở mức 1 thay vì 0? Có cách nào để làm điều đó trực tiếp trong mã?Làm cách nào để tạo một ArrayList với chỉ mục bắt đầu là 1 (thay vì 0)

(Lưu ý rằng tôi đang yêu cầu ArrayList, đối với mảng đơn giản xin vui lòng xem Initializing an array on arbitrary starting index in c#)

+14

Tại sao bạn muốn? – Eric

+0

@Eric Tôi sẽ nói lý do tại sao, trong năm đầu tiên ở trường đại học, sinh viên học Pascal và lập chỉ mục ở đây bắt đầu từ 1 nên họ hỏi họ có thể làm điều tương tự với C# (chỉ là câu hỏi) không. –

+0

Còn 0,5? :) –

Trả lời

17

Các cách rõ ràng để làm điều đó sẽ được quấn một ArrayList trong việc thực hiện của riêng bạn, và trừ 1 từ indexer trong mọi hoạt động sử dụng chỉ mục.

Bạn thực tế cũng có thể khai báo một mảng trong .NET, có một số arbitrary lower bound (Cuộn xuống phần "Tạo mảng có giới hạn dưới không").

Với điều đó đã nói, vui lòng không làm điều đó trong mã sản xuất. Điều quan trọng là nhất quán.

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

Vâng, bạn có thể làm của riêng bạn:

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

Nhưng nó đặt ra câu hỏi: tại sao trên trái đất bạn sẽ bận tâm?

1

Như các câu trả lời khác được đề xuất, có nhiều cách để mô phỏng điều này, nhưng không có cách nào trực tiếp để thực hiện việc này bằng C# hoặc các ngôn ngữ .NET thường được sử dụng khác. Trích dẫn Eric Gunnerson:

Các CLR không hỗ trợ loại xây dựng (Tôi đã có một thời gian khó khăn không sử dụng thuật ngữ "trò hề" ở đây ...), nhưng không có, để kiến ​​thức của tôi, bất kỳ các ngôn ngữ có cú pháp dựng sẵn để làm điều đó.

2

Tôi không biết nếu nó vẫn còn, nhưng tại một thời điểm, Visual Basic sẽ cho phép bạn bắt đầu chỉ mục mảng của bạn tại 1 với Option Base 1.

Trong C#, không có bộ sưu tập System.Collections nào hỗ trợ điều này, nhưng bạn luôn có thể viết lớp trình bao bọc thực hiện việc dịch chỉ mục cho bạn.

Thực sự, tuy nhiên, điều này nên tránh. VB của Option Base tạo ra nhiều vấn đề hơn nó giải quyết, tôi tưởng tượng bởi vì nó đã phá vỡ các giả định và làm những điều khó hiểu hơn.

7

Một lý do chính đáng để làm điều này là viết các bài kiểm tra đơn vị. Một số SDK bên thứ ba nhất định (ví dụ: Excel COM interop) mong bạn làm việc với các mảng có chỉ mục dựa trên một. Nếu bạn đang làm việc với một SDK như vậy, bạn có thể và nên phân tích chức năng này trong khung kiểm tra C# của bạn.

Sau đây nên làm việ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?"); 

Tôi không biết nếu nó có thể đúc này như một mảng C# phong cách tiêu chuẩn. Chắc là không. Tôi cũng không biết cách mã hóa cứng các giá trị ban đầu của một mảng như vậy, ngoài vòng lặp để sao chép chúng từ một mảng C# chuẩn với các giá trị ban đầu được mã hóa cứng. Không thiếu sót nào trong số những thiếu sót này phải là một vấn đề lớn trong mã thử nghiệm.

+0

Tôi nhận thấy rằng nhận xét của tôi áp dụng cho mảng, không phải mảng ArrayLists. Rất tiếc. Tôi hy vọng những người làm việc với Excel và VTSO sẽ vẫn thấy nó hữu ích, mặc dù nó không có câu hỏi gốc. –

1

Đây là điều mà tôi đang sử dụng ngay bây giờ để nhanh chóng cổng một ứng dụng VBA để C#:

Đây là một lớp mảng mà bắt đầu với 1 và chấp nhận nhiều chiều.

Mặc dù có một số công việc bổ sung cần thực hiện (IEnumerator, v.v ...), đó là sự khởi đầu và đủ cho tôi vì tôi chỉ sử dụng các bộ chỉ mục.

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

Điều này thật tuyệt vời! Tôi đang chuyển đổi một số trò chơi Spectrum Basic cũ và điều này là vô giá. – Shevek

+0

Rất vui được! :) – Larry

0

Trước tiên, hãy để tôi mở đầu câu trả lời này bằng cách giải thích trường hợp sử dụng của tôi: Excel Interop. Nó dễ dàng hơn nhiều để đọc và ghi dữ liệu bằng cách sử dụng mảng, nhưng Excel Range.Value2 kỳ diệu trả về một mảng đối tượng dựa trên 1.

Vì vậy, nếu bạn đang viết thư cho Excel và đó là lý do bạn đặt câu hỏi này ngay từ đầu ... thì có lẽ dừng chiến đấu C# và để Excel khởi tạo mảng cho bạn. Vì vậy, thay vì:

object[,] newArray = new object[indexR, indexC]; 

Bạn có thể sử dụng:

object[,] newArray = (object[,])RangeToWriteTo.Value2; 

Trong trường hợp của tôi, tôi đã tạo ra một lớp wrapper để cho phép tôi sử dụng một mảng cho các thuộc tính như sau:

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

Vì vậy, trong mọi trường hợp, tôi đang đọc từ cùng một chỉ mục. Vì vậy, để thực hiện chuyển đổi từ một mô hình tôi đang đi vào một phương pháp tạo, tôi chỉ cần sao chép các thuộc tính vào mô hình sử dụng mảng được tạo ra từ Excel.

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

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

      writeRange.Value2 = insertingModel.data; 

Điều này làm việc cho tôi vì tôi chỉ phải thực hiện việc này trong chức năng tạo. Trong bản cập nhật/get/delete, bạn sẽ nhận được mảng dựa trên Excel. Có lẽ một cải tiến trong tương lai sẽ là tạo ra một nhà máy sản xuất phạm vi Excel tránh được việc xây dựng mặc định dựa trên 0, nhưng giải pháp này chỉ cho tôi thử nghiệm trên các thử nghiệm của tôi, vì vậy tôi đang tiếp tục!

Các vấn đề liên quan