Arrays with non-zero upper and lower bounds…

In the comments to my post on zero and one based arrays, several people mentioned that they wanted to be able to have collections that ran from 4 to 10, or from 1900 to 2004 for years. Consider the following:

public class YearClass
const int StartDate = 1900;
const int EndDate = 2050;
int[] arr = new int[EndDate – StartDate + 1];

public int this[int num]
get { return arr[ num – StartDate]; }
set { arr[num – StartDate] = value; }

public class Test
public static void Main()
YearClass yc = new YearClass();
yc[1950] = 5;

I think that gives you the user model that you want.

Comments (11)

  1. Bill says:

    That’s nice. Very nice solution for right now, with current tools.

    But what we really want is to code our business problems declaratively. So if you built a little collection-class code generator that would build that little bit of code, plus bounds checking, that would be totally awesome.

    Essentially, we don’t want to be bothered with error-prone code, cut-and-pasted from collection to collection, that we must worry about testing in each every location that it’s used. We just want to use a relatively direct model of our businesses.

    MS has done a really great job with the low-level stuff. Now let’s build some use

    P.S. Challenge/Puzzle

    Could the code you published by refactored into and Interface or Base class, so that all such collections provide start and end indexes in exactly the same way?

  2. Rick Ross says:

    In order to avoid a System.IndexOutOfRangeException, I would check the index to insure that it is within the appropriate range.

  3. Steve Maine says:

    public class OffsetArray<T>


    readonly int start;

    readonly int end;

    T[] arr;

    public OffsetCollection<T>( int start, int end)


    this.start = start;

    this.end = end;

    this.arr = new T[ end – start + 1];


    public T this[int num]


    get { return arr[ num – start]; }

    set { arr[num – start] = value; }



    You’d probably want to sanity check start and end in the constructor. Requesting an index that’s out of range *should* throw an IndexOutOfRangeException, IMHO.

  4. You know I looked at that and thought "why didn’t I think of that?" The reason is of course that I’ve been programming too long with the old model of programming and things like this, which should probably be obvious to someone who has really internalized OOP, don’t come natural to me. This will get me thinking in some new directions. Thanks.

  5. Rick Ross says:

    Steve, in most cases, I would tend to agree with you that throwing an IndexOutOfRangeException would be appropriate. However, in this case, it would be more appropriate, IMHO, to raise a custom expression like DateOutOfRangeException. This gives the user of the class a better clue as to what the problem is.

  6. Dilton McGowan II says:

    What do templates have to do with C#? Surely they aren’t going to show up in future versions since that would uglify the currently readable C# syntax. Eric’s solution is ok for now. Just move that into the core and call it a day.

  7. Thomas Eyde says:

    Shouldn’t it be StartYear, EndYear and YearOutOfRangeException? I think IndexOutOfRangeException is just fine, because I am after all indexing it.

  8. Douglas McClean says:

    You can also use Array.CreateInstance(Type, int[], int[]) to create an array with a specified element type, and specified dimensionality, lengths, and lower bounds.