108

From what I can tell, .NET 4.0 still lacks read-only lists. Why does the framework still lack this functionality? Isn't this one of the commonest pieces of functionality for domain-driven design?

One of the few advantages Java has over C# is this in the form of the Collections.unmodifiablelist(list) method, which it seems is long overdue in IList<T> or List<T>.

Using IEnumerable<T> is the easiest solution to the question - ToList can be used and returns a copy.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chris S
  • 64,770
  • 52
  • 221
  • 239
  • Seems like the only real way to have a true read only `List` is to write your own, there is no built in class that I know of that supports all of the "read only" features of `List` out of the box like `Contains`, LINQ queries, etc. – jrh Aug 17 '17 at 12:37

7 Answers7

156

You're looking for ReadOnlyCollection, which has been around since .NET2.

IList<string> foo = ...;
// ...
ReadOnlyCollection<string> bar = new ReadOnlyCollection<string>(foo);

or

List<string> foo = ...;
// ...
ReadOnlyCollection<string> bar = foo.AsReadOnly();

This creates a read-only view, which reflects changes made to the wrapped collection.

Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 1
    I feel a bit stupid having asked this question now - and not known about ReadOnlyCollection – Chris S Jun 12 '09 at 08:56
  • 59
    don't be - neither did I, when I went looking for the same thing and found Your question – Roland Tepp Feb 21 '11 at 11:33
  • 10
    That's an annoyingly hard class to find. It's in the System.Collections.ObjectModel namespace instead of System.Collections.Generic where I would expect to find it. I suppose it's because that's where it was before the Generic namespace existed. Still I would expect the base class to remain in ObjectModel and the generic class to be added to Generic. I suppose they had their reasons, but I find it annoying. – BlueMonkMN Sep 28 '12 at 14:43
  • 1
    ReadOnlyCollection is still user editable, the Items property retrieves the base list, and you can then use standard Add/Remove functions on the base list? – Denise Skidmore Jun 28 '13 at 19:26
  • 5
    @BlueMonkMN : Please refer this [article](http://blogs.msdn.com/b/kcwalina/archive/2005/03/15/396086.aspx) to find out why it's seperate from the Collections.Generic namespace. – Uchitha Jul 23 '13 at 06:17
  • 7
    But that's not a List, it's a Collection. So if you use it, you need to modify all your code to use Collection instead of List. – Roman Zabicki May 25 '16 at 13:50
  • 1
    Why it doesn't provide linq capabilities like Where or FirstOrDefault? Neither does IReadOnlyList. – Alireza Ahmadi Rad Sep 18 '16 at 14:13
  • @AlirezaAhmadiRad Also, neither the interface or `ReadOnlyCollection` has methods like `Contains`, it's a bit disappointing. – jrh Aug 17 '17 at 12:32
  • Further to comment above by Uchitha, the "article" has a new link, here: https://learn.microsoft.com/en-us/archive/blogs/kcwalina/the-reason-why-collection-readonlycollection-and-keyedcollection-were-moved-to-system-collections-objectmodel-namespace – erict Mar 15 '20 at 00:52
14

For those who like to use interfaces: .NET 4.5 adds the generic IReadOnlyList interface which is implemented by List<T> for example.

It is similar to IReadOnlyCollection and adds an Item indexer property.

d219
  • 2,707
  • 5
  • 31
  • 36
Martin
  • 5,165
  • 1
  • 37
  • 50
13

How about the ReadOnlyCollection already within the framework?

d219
  • 2,707
  • 5
  • 31
  • 36
Jason Watts
  • 1,086
  • 5
  • 13
11

If the most common pattern of the list is to iterate through all the elements, IEnumerable<T> or IQueryable<T> can effectively act as a read-only list as well.

d219
  • 2,707
  • 5
  • 31
  • 36
Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • 4
    If you expose your List as an IEnumerable, then the consumer could simply cast it back to List and modify it. – JulianR Jun 11 '09 at 22:36
  • 4
    Of course, but it's not intended to be a bulletproof measure - you could also probably read the private fields and track down the original list. It's more as describing the intent that this should stay read-only. – Ana Betts Jun 11 '09 at 22:48
  • 5
    You're not modifying the original list by calling `ToList()` either, just a copy – Chris S May 25 '11 at 20:57
  • Note that `IEnumerable` is not a complete set of "read only" methods, for example it does not contain methods like `Contains`. – jrh Aug 17 '17 at 12:31
8

In 2.0 you can call AsReadOnly to get a read-only version of the list. Or wrap an existing IList in a ReadOnlyCollection<T> object.

d219
  • 2,707
  • 5
  • 31
  • 36
Paul Alexander
  • 31,970
  • 14
  • 96
  • 151
  • that's the equivalent of Collections.unmodifiablelist(list) I was after – Chris S Jun 12 '09 at 10:49
  • I missed this in .NET 4 because I was using an IList instead of a true List. Make sure to notice that AsReadOnly is still available in .NET 4 so long as you're dealing with a a List. – BlueMonkMN Sep 28 '12 at 14:47
7

What's wrong with System.Collections.ObjectModel.ReadOnlyCollection?

Matthew Dresser
  • 11,273
  • 11
  • 76
  • 120
0

Create an extension method ToReadOnlyList() on IEnumerable, then

IEnumerable<int> ints = new int[] { 1, 2, 3 };
var intsReadOnly = ints.ToReadOnlyList();
//intsReadOnly [2]= 9; //compile error, readonly

here is the extension method

public static class Utility
{
    public static IReadOnlyList<T> ToReadOnlyList<T>(this IEnumerable<T> items)
    {
        IReadOnlyList<T> rol = items.ToList();
        return rol;
    }
}

see Martin's answer too

Rm558
  • 4,621
  • 3
  • 38
  • 43