I had exactly the same idea as Jon Skeet: implement a wrapper around a T[]
that provides random access by index, automatically handling the adjustment of indexed access for you.
I threw together a quick implementation just now (skip ahead to the bottom of this answer for a short demo):
public struct ArrayFragment<T> : IList<T>
{
private T[] _source;
private int _start;
private int _count;
public ArrayFragment(T[] source, int start, int count)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (start < 0 || start >= source.Length)
{
throw new ArgumentOutOfRangeException("start");
}
if (count > source.Length - start)
{
throw new ArgumentOutOfRangeException("count");
}
_source = source;
_start = start;
_count = count;
}
public T this[int index]
{
get { return _source[_start + index]; }
}
public int Count
{
get { return _count; }
}
public bool Contains(T value)
{
int index = Array.IndexOf(_source, value, _start, _count);
return index != -1;
}
public void CopyTo(T[] destination, int index)
{
Array.Copy(_source, _start, destination, index, _count);
}
public int IndexOf(T value)
{
int index = Array.IndexOf(_source, value, _start, _count);
return index != -1 ? index - _start : -1;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _count; ++i)
{
yield return _source[_start + i];
}
}
#region Explicit Interface Implementation
// a bunch of explicitly implemented IList<T> members
// that all throw a NotSupportedException
#endregion
}
Here's a demo:
int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try
{
var fragment = new ArrayFragment<int>(numbers, 2, 5);
Console.WriteLine("Iterating using foreach: ");
foreach (int number in fragment)
{
Console.WriteLine(number);
}
Console.WriteLine("Iterating using for: ");
for (int i = 0; i < fragment.Count; ++i)
{
Console.WriteLine(fragment[i]);
}
Console.WriteLine("Index of 4: {0}", fragment.IndexOf(4));
Console.WriteLine("Index of 1: {0}", fragment.IndexOf(1));
Console.WriteLine("Index of 9: {0}", fragment.IndexOf(9));
Console.WriteLine("Index of 7: {0}", fragment.IndexOf(7));
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
Output:
Iterating using foreach:
3
4
5
6
7
Iterating using for:
3
4
5
6
7
Index of 4: 1
Index of 1: -1
Index of 9: -1
Index of 7: 4