Is it possible to somehow mark a System.Array
as immutable. When put behind a public-get/private-set they can\'t be added to, since it requires re-allocation a
Please see Immutable Collections Now Available in the base class library (currently in preview).
.NET tends to steer away from arrays for all but the simplest and most traditional use cases. For everything else, there are various enumerable/collection implementations.
When you want to mark a set of data as immutable, you're going beyond the capability provided by a traditional array. .NET provides equivalent capability, but not technically in the form of an array. To get an immutable collection from an array, use Array.AsReadOnly<T>:
var mutable = new[]
{
'a', 'A',
'b', 'B',
'c', 'C',
};
var immutable = Array.AsReadOnly(mutable);
immutable
will be a ReadOnlyCollection<char> instance. As a more general use case, you can create a ReadOnlyCollection<T> from any generic IList<T> implementation.
var immutable = new ReadOnlyCollection<char>(new List<char>(mutable));
Note that it has to be a generic implementation; plain old IList won't work, meaning that you can't use this method on a traditional array, which only implements IList. This brings to light the possibility of using Array.AsReadOnly<T> as a quick means of obtaining access to generic implementations that are normally inaccessible via a traditional array.
ReadOnlyCollection<T> will give you access to all of the features that you would expect from an immutable array:
// Note that .NET favors Count over Length; all but traditional arrays use Count:
for (var i = 0; i < immutable.Count; i++)
{
// this[] { get } is present, as ReadOnlyCollection<T> implements IList<T>:
var element = immutable[i]; // Works
// this[] { set } has to be present, as it is required by IList<T>, but it
// will throw a NotSupportedException:
immutable[i] = element; // Exception!
}
// ReadOnlyCollection<T> implements IEnumerable<T>, of course:
foreach (var character in immutable)
{
}
// LINQ works fine; idem
var lowercase =
from c in immutable
where c >= 'a' && c <= 'z'
select c;
// You can always evaluate IEnumerable<T> implementations to arrays with LINQ:
var mutableCopy = immutable.ToArray();
// mutableCopy is: new[] { 'a', 'A', 'b', 'B', 'c', 'C' }
var lowercaseArray = lowercase.ToArray();
// lowercaseArray is: new[] { 'a', 'b', 'c' }
The only thing to add is that Arrays imply mutability. When you return an Array from a function, you are suggesting to the client programmer that they can/should change things.