I've got the extremely unlikely and original situation of wanting to return a readonly array from my property. So far I'm only aware of one way of doing it - through the System.Collections.ObjectModel.ReadOnlyCollection<T>
. But that seems somehow awkward to me, not to mention that this class loses the ability to access array elements by their index (added: whoops, I missed the indexer). Is there no better way? Something that could make the array itself immutable?

- 104,512
- 87
- 279
- 422
-
3ReadOnlyCollection has an indexer, it supports indexing. You can't make an array immutable. – Hans Passant Jan 25 '10 at 16:17
-
1Actually, ReadOnlyCollection
**does** have an indexer property... – BFree Jan 25 '10 at 16:18 -
1@BFree - but (importantly) it won't let you successfully reassign items via the indexer – Marc Gravell Jan 25 '10 at 16:28
-
7@nobugz - sure you can: `new string[0]` - plenty immutable ;-p – Marc Gravell Jan 25 '10 at 16:29
-
23Two points: (1) we are *considering* immutable arrays for a future version of C#, but it is quite tricky; how do you initialize the array if its contents cannot be changed? We're working on it, but no promises, this is just at the idea stage. And (2) don't forget that a read only collection is only an immutable facade over a mutable object; if someone else mutates the underlying object, the facade will expose the mutation. – Eric Lippert Jan 25 '10 at 17:02
-
@Eric Lippert: For #1, would it be possible to make it like Java's `final` keyword? With `final` you're allowed to set the variable once and only once. So you could declare a class level final array variable, set that in your object's constructor and it would not change at runtime (#2 notwithstanding). – jasonh Jan 25 '10 at 18:36
-
1@JasonH. Declaring something final in Java works the same as readonly in C#. You are only declaring the reference to the array as final and not the contents. – RichardOD Jan 25 '10 at 18:49
-
True, but then why was he asking how to initialize the array? Maybe there's some sort of misunderstanding about the word initialize here. When I think of initialization, I think of: `myArray = new MyObject[50];` not `myArray[0] = new MyObject();`. If you wanted to prevent the latter from being done over and over again, why not initialize a new array and then assign it like so: `myReadonlyArray = myTempArray`. Then couldn't they effectively prevent someone from reassigning the contents of one entry in the array. I realize though, you can still mutate the entries in the array, if they support it – jasonh Jan 25 '10 at 22:18
-
1@Eric - #1 - make it like readonly - initializable only in constructor. Although I suppose this is such an obvious answer that you have already considered it and there are good reasons against it. #2 - in my case it's a static collection. It doesn't ever change, and I want to ensure that there is no code that can change it. The original array is therefore promptly discarded after creating the ReadOnlyCollection wrapper. Then the only way of changing it is through impolite reflection. – Vilx- Jan 25 '10 at 22:39
8 Answers
Use ReadOnlyCollection<T>
. It is read-only and, contrary to what you believe, it has an indexer.
Arrays are not immutable and there is no way of making them so without using a wrapper like ReadOnlyCollection<T>
.
Note that creating a ReadOnlyCollection<T>
wrapper is an O(1) operation, and does not incur any performance cost.
Update
Other answers have suggested just casting collections to the newer IReadOnlyList<T>
, which extends IReadOnlyCollection<T>
to add an indexer. Unfortunately, this doesn't actually give you control over the mutability of the collection since it could be cast back to the original collection type and mutated.
Instead, you should still use the ReadOnlyCollection<T>
(the List<T>
method AsReadOnly()
, or Array
s static method AsReadOnly()
helps to wrap lists and arrays accordingly) to create an immutable access to the collection and then expose that, either directly or as any one of the interfaces it supports, including IReadOnlyList<T>
.

- 17,853
- 3
- 55
- 72

- 61,417
- 20
- 137
- 189
-
6`ReadOnlyCollection` is not usable as an immutable collection. It is a little _less_ than an Array, but with _more_ code around it. It's only 'feature' is not to allow its _users_ to modify the collection, but it does not even guarantee that to the users... Bottom line: useless! – gatopeich Mar 07 '12 at 15:59
-
14@gatopeich: Useless is an unfounded statement. Please provide your sources as to its lack of use. Nice rant, though. – Jeff Yates Mar 07 '12 at 16:19
-
1I wish there was IReadOnlyList interface that this class would implement. – Kugel Dec 26 '12 at 17:09
-
@gatopeich: Why do you say that it is useless, it is an implementation of `IList
` that fails if you try and use the modification calls while using an `IList – Guvante Sep 26 '13 at 20:55` as its backend. Sure it doesn't make 100% certain the data is immutable, but it is the best you can do without copying the data (which seems silly, since it is almost always used by a class that otherwise ensures the backing collection is not changed) -
@JeffYates is there a performance benefit to using a ReadOnlyCollection
? – Kyle B. Dec 18 '13 at 21:23 -
Over a non-read only one? I don't expect so, though I would need to test it to be sure. – Jeff Yates Dec 19 '13 at 15:44
-
2
-
Turns out this is nearly ten times as slow when iterating over it than an array. The search continues. – Mike-E Mar 09 '17 at 15:06
-
1@Mike-EEE: On small arrays, it does seem to be the case that it is ~10 times slower. However, on larger arrays, it is closer to ~2 times slower. Not ideal, I agree, though I have to wonder what you're doing that means the perf is important in this situation. I just did a 100 million iteration test and it took less than a second. – Jeff Yates Mar 11 '17 at 17:59
-
1@JeffYates The tests that I ran were consistently ~10x slower, and I ran them with 100,000 items and 10,000 items. FWIW I was using Benchmark.NET. Additionally, I ended up using `ImmutableArray
`, although it is a value type and this leads to boxing when using (linq) extension methods, which also impacts performance. No clear winner here. – Mike-E Mar 12 '17 at 18:30 -
1@Mike-EEE There is no boxing in this case, because the extension methods used by Linq are specialized for this specific type. These methods live in the `ImmutableArrayExtensions` class. – Miguel Angelo Feb 02 '18 at 18:21
-
@MiguelAngelo I meant the extension methods that `ImmutableArrayExtensions` doesn't cover. While there are a number of methods there, they are a small subset of what is found in the rest of the Linq universe. :) – Mike-E Feb 02 '18 at 21:51
.NET Framework 4.5 introduced IReadOnlyList<T>
which extends from IReadOnlyCollection<T>
adding T this[int index] { /*..*/ get; }
.
You can cast from T[]
to IReadOnlyList<T>
. One advantage of this is that (IReadOnlyList<T>)array
understandably equals array
; no boxing is involved.
Of course, as a wrapper is not being used, (T[])GetReadOnlyList()
would be mutable.

- 7,237
- 1
- 31
- 49
-
1The issue with just casting to the interface is that it can be cast back again, as you point out. This means you have no control over the mutability of the data. You should still use the `ReadOnlyCollection
` to wrap first and then use the `IReadOnlyList – Jeff Yates Aug 05 '15 at 15:09` from that so that you have control over how your data is used. -
18I'd argue this boils down to contracts: If I return you an object, then I've given you permission to use whatever methods are exposed by that object. If you decide to, for example, use reflection to peek and manipulate the innards of that object, then all guarantees are lost. Likewise, if I return you an IEnumerable
, then I've given you the right to enumerate results. If you decide to directly cast the IEnumerable to a List – Warty Aug 19 '15 at 08:01and clear it (read: `(List )result` over `result.ToList()`), then you're working with behavior that I have not defined. -
2Note that iterating through this is nearly ten times slower than iterating through an array. – Mike-E Mar 09 '17 at 15:14
-
Update: In .NET Core there's now ReadOnlySpan, which is probably going to be more performant than the above. I haven't had the chance to use it yet, though. – Warty Dec 10 '17 at 22:28
From .NET Framework 2.0 and up there is Array.AsReadOnly which automatically creates a ReadOnlyCollection wrapper for you.

- 2,138
- 19
- 32
If you really want an array returned, but are afraid that the consumer of the array will mess with the internal data, just return a copy of the Array. Personally I still think ReadOnlyCollection<T>
is the way to go, but if you REALLY want an array.....

- 102,548
- 21
- 159
- 201
-
3Seems like a good idea, until you realise what class.MyArray[i] will do in a loop. Do that 1000 times and you have 1000 copies of the array! – RichardOD Jan 25 '10 at 16:33
-
@RichardOD True, but you don't do that. If you're accessing it by index on the main class, then you just return the elements. If you're returning the array then give the user a function that will return a copy of the array, and iterate over that. – Patrick M Apr 09 '13 at 17:59
I recognise that this is an old question, but there are packages for .NET now that contain an ImmutableArray type. Built in to .NET Core 3, and available via NuGet for Full framework 4.5 onwards

- 7,858
- 4
- 34
- 49
IEnumerable comes to mind.

- 17,275
- 20
- 88
- 141
-
Do you mean to cast my array to an IEnumerable and return that? That would then be even worse than the ReadOnlyCollection. First of all, anyone could easily cast it back to the array and modify it. Secondly it provides an even smaller subset of the functionality that arrays offer. – Vilx- Jan 25 '10 at 16:18
-
5You can make this work just fine with an iterator (yield return statement). – Hans Passant Jan 25 '10 at 18:07
You might want to implement the IEnumerable interface and overload the this[int] operator to deny access to it's setter
-
1Say what? In what way is it better than ReadOnlyCollection mentioned above? – Vilx- Jan 25 '10 at 16:39
-
3translation: "you may want to implement an interface but not implement it" -1 – Andrew Bullock May 15 '12 at 09:36
There is now support for Immutable collections. See https://www.nuget.org/packages/System.Collections.Immutable
This supports any of the following:
- .NET 4.5 (or higher)
- .NETStandard 1.0 (or higher)
- Windows 8.0
- WindowsPhone 8.0
- WindowsPhoneApp 8.1
- Portable Class Library (.NETFramework 4.5, Windows 8.0, WindowsPhone 8.0, WindowsPhoneApp 8.1)