You know probably the following problem: You want to share a collection between two objects A and B (or similarly want to expose a collection by a property) and ... well, you realize that this is actually not a good idea since both A and B can then modify the collection and blah blah armageddon now ...
But often you realize that you don't want to share the collection as a whole but only want to initialize an object with the items of the collection or pass the items to a method of the object. Furthermore the items of the object don't change during the lifetime of an object, so you often end up doing things like this:
public class Foo
{
private List<int> items;
public Foo(IEnumerable<int> items)
{
this.items = items.ToList();
}
public ReadOnlyCollection<int> Items
{
get { return new ReadOnlyCollection(this.items); }
}
}
Both .ToList() and the ReadonlyCollection-Wrapper provide a reasonable solution to the problem but the also suffer from some problems: .ToList() copies the whole List - so I end up having x instances of the same collection while the ReadOnlyCollection only ensures that clients don't change the collection but don't give any guarantee to the clients that the collection won't change.
Actually this is a situation I am quite often confronted with because most of the classes I write (guessing: 80 - 90 %) are effectively immutable and aggregate often collections which basically represent immutable arrays (meaning in this context: a fixed-size immutable sequence of items). From my point of view a good solution to this problem is quite simple: Build a wrapper class for an array which is guaranteed to be initialized properly in the constructor and provide only methods/properties that don't change the underlying array.
Long story short: Is there anything wrong with the following (trivial) implementation of the concept of an immutable array?
Btw: I decided that Sequence is an appropriate name since a) it describes the intention quite good (a fixed-size immutable sequence of items) b) it is not a name currently used by .net and c) it is very short which is important because I am planning to use it extensively.
public sealed class Sequence<T> : IEnumerable<T>
{
private readonly T[] items;
public Sequence(IEnumerable<T> items)
{
this.items = items.ToArray();
}
public Sequence(int size, Func<int, T> producer)
{
this.items = new T[size];
for (int i = 0; i < size; i++)
{
this.items[i] = producer(i);
}
}
public T this[int i]
{
get { return this.items[i]; }
}
public int Length
{
get { return this.items.Length; }
}
public bool Contains(T item)
{
for (int i = 0; i < this.items.Length; i++)
{
if (this.items[i].Equals(item))
return true;
}
return false;
}
public Enumerator<T> GetEnumerator()
{
return new Enumerator<T>(this);
}
IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public struct Enumerator<T> : IEnumerator<T>
{
private T[] items;
private int nextIndex;
private T current;
internal Enumerator(Sequence<T> immutableArray)
{
this.items = immutableArray.items;
this.nextIndex = 0;
this.current = default(T);
}
public T Current
{
get { return this.current; }
}
object System.Collections.IEnumerator.Current
{
get { return this.Current; }
}
public void Dispose()
{
}
public bool MoveNext()
{
if (this.nextIndex < this.items.Length)
{
this.current = this.items[this.nextIndex];
this.nextIndex++;
return true;
}
else
{
return false;
}
}
public void Reset()
{
this.nextIndex = 0;
this.current = default(T);
}
}
}