52

I have some class with List-property:

class Foo {
  private List<int> myList;
}

I want provide access to this field only for read.

I.e. I want property with access to Enumerable, Count, etc. and without access to Clear, Add, Remove, etc. How I can do it?

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
AndreyAkinshin
  • 18,603
  • 29
  • 96
  • 155
  • I'm going to go a head and change the title of this question to read-only because read-only and immutability are two very different albeit related topics, I'd prefer it if we did not mix them. If you're looking for immutability check out http://stackoverflow.com/a/9009748/58961. – John Leidegren Mar 09 '13 at 17:04
  • Possible duplicate of [Read-only list or unmodifiable list in .NET 4.0](https://stackoverflow.com/questions/984042/read-only-list-or-unmodifiable-list-in-net-4-0) – StayOnTarget Sep 27 '18 at 12:08
  • Starting with .NET Core 1.0 (and .NET 5), the library includes all sorts of immutable collections. See [System.Collections.Immutable Namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.immutable?view=net-6.0#classes). The difference between immutable and read-only collections in short: an instance of an immutable collection is read-only *and* unchangeable. Instances of read-only collections are wrappers that allow the owner of the wrapped collection to change it. From the consumer perspective, a read-only collection could change at any time while an immutable never will. – BionicCode Aug 27 '22 at 10:47

5 Answers5

77

You can expose a List<T> as a ReadOnlyCollection<T> by using the AsReadOnly() method

C# 6.0 and later (using Expression Bodied Properties)

class Foo { 

  private List<int> myList;

  public ReadOnlyCollection<int> ReadOnlyList => myList.AsReadOnly();

}

C# 5.0 and earlier

class Foo {

  private List<int> myList;

  public ReadOnlyCollection<int> ReadOnlyList {
     get {
         return myList.AsReadOnly();
     }
  }
}
FearlessHyena
  • 3,527
  • 33
  • 39
43

If you want a read-only view of a list you could use ReadOnlyCollection<T>.

class Foo {
    private ReadOnlyCollection<int> myList;
}
Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 5
    Or, more accurately, a private `List` variable and a public `ReadOnlyCollection` property with a `get {}` that returns the variable. – Victor Nicollet Jan 13 '11 at 12:34
  • 5
    @Victor: that would give calling code access to the mutable list by a simple cast. Probably not what the OP wants. The readonly property could `return new ReadOnlyCollection(myList);` though. – Fredrik Mörk Jan 13 '11 at 12:35
  • 10
    ReadOnlyCollection is not really immutable as it contains a pointer to the original list - if you add something to your list, the readOnly-instance can access this new item either... but, you are right, when it comes down to modifications-methods - these are missing! –  Jan 13 '11 at 12:36
  • @Andreas: the OP does not state that the list content must not change; the only requirement given is that the calling code must not be able to change it. – Fredrik Mörk Jan 13 '11 at 12:39
  • @Fredrik: this is what I meant (and expressed quite awkwardly, I admit) ;-) – Victor Nicollet Jan 13 '11 at 12:42
  • @Fredrik Mörk: my comment was just for mentioning a side-effect –  Jan 13 '11 at 13:35
  • 1
    @FredrikMörk: because the title says "immutable". Perhaps it should be changed to "readonly". – David Schmitt Sep 25 '12 at 07:45
9

There is now an Immutable Collections library that does exactly that. Which you can install via nuget.

The immutable collection classes are supported starting with the .NET Framework 4.5.

https://msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx

The System.Collections.Immutable namespace provides generic immutable collection types that you can use for these scenarios, including: ImmutableArray<T>, ImmutableDictionary<Tkey,TValue>, ImmutableSortedDictionary<T>, ImmutableHashSet<T>, ImmutableList<T>, ImmutableQueue<T>, ImmutableSortedSet<T>, ImmutableStack<T>

Example of Usage:

class Foo
{
    public ImmutableList<int> myList { get; private set; }

    public Foo(IEnumerable<int> list)
    {
        myList = list.ToImmutableList();
    }
}
K. R.
  • 1,220
  • 17
  • 20
  • ImmutableList DOES allow you to add new elements, it just creates another list object for that. `Note that these methods return a new object. When you add or remove items from an immutable list, a copy of the original list is made with the items added or removed, and the original list is unchanged.` This answer shouldn't be upvoted. – AymenDaoudi Oct 08 '21 at 17:52
  • @AymenDaoudi The terms "immutable" or "read-only" refer to the actual instance. *"[...] return a new object."* means "return a new instance", where the original instance remains in its original state. Distributing an accessible immutable list in fact prevents the consumer to mutate it. They will always modify a copy. A read-only collection on the other hand is not immutable as it can be modified via the underlying i.e. wrapped collection. In other words: retrieving an immutable collection instance guarantees the consumer that this instance will never change. – BionicCode Aug 27 '22 at 09:54
  • 1
    @AymenDaoudi This means, an instance of `ImmutableList` is read-only (it implements `IReadOnlyList` and *in addition* it is immutable (unchangeable). Whether the OP needs the list to be immutable or not is not stated in the question. Since I believe that it is really worth to consider to make the returned instance immutable, I find this a valid answer which gives the OP or any reader that looks for a solution regarding a similar problem a valuable choice. Hence this answer qualifies for an upvote. – BionicCode Aug 27 '22 at 09:57
  • 1
    `ImmutableList` is available without installing additional packages. It is now included in .NET Core and .NET 5 or later. See [System.Collections.Immutable Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable?view=net-6.0#classes). – BionicCode Aug 27 '22 at 10:00
  • @AymenDaoudi The original title of this question even explicitly asked for an immutable list. – BionicCode Aug 27 '22 at 10:02
9

i would go for

public sealed class Foo
{
    private readonly List<object> _items = new List<object>();

    public IEnumerable<object> Items
    {
        get
        {
            foreach (var item in this._items)
            {
                yield return item;
            }
        }
    }
}
3

If you declare a readonly list in your class, you'll still be able to add items to it.

If you don't want to add or change anything, you should be using ReadOnlyCollection<T> as Darin suggested.

If you want to add, remove items from the list but don't want to change the content, you can use a readonly List<T>.

Pabuc
  • 5,528
  • 7
  • 37
  • 52