---
title: "ReadOnlySet<T> in .NET 9"
description: "The next preview (preview 6) will bring a new type `ReadOnlySet<T>`. This is a read-only set that is similar to `ReadOnlyCollection<T>`. Let's see how it works and why it was introduced."
updated: 2024-06-26
tags: ["C#", ".NET", ".NET 9"]
canonical: "https://steven-giesel.com/blogPost/f368c7d3-488e-4bea-92b4-abf176353fa3/readonlysett-in-net-9"
---

# ReadOnlySet<T> in .NET 9

The next preview (preview 6) will bring a new type `ReadOnlySet<T>`. This is a read-only set that is similar to `ReadOnlyCollection<T>`. Let's see how it works and why it was introduced.

So what does that new try to solve? Well, there are two issues with the "current" approach. <sup>Current as in .NET 8</sup>

## 1. `IReadOnlySet` isn't enough
For sure, we already have the [`IReadOnlySet<T>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlyset-1?view=net-8.0) interface. So why isn't that enough? Let's have a look at `List<T>` and `IReadOnlyList<T>`, which suffers somewhat from the same issue.

```csharp
var list = new List<int> { 1, 2, 3 };
IReadOnlyList<int> readOnlyList = list;

// You can easily cast it back to a List<T> and modify it
var list2 = (List<int>)readOnlyList;
list2.Add(4);
```

Of course, consumers of your API shouldn't do that, but you can't prevent it. The same applies to `IReadOnlySet<T>`. So that is why we have a `AsReadOnly` on `List`:

```csharp
var list = new List<int> { 1, 2, 3 };
var readOnlyList = list.AsReadOnly();

// You can't cast it back to a List<T>
var list2 = (List<int>)readOnlyList; // Exception
```

That is exactly what `ReadOnlySet<T>` will do for `IReadOnlySet<T>`:
```csharp
var set = new HashSet<int> { 1, 2, 3 };
var readonlySet = new ReadOnlySet<int>(set);
```

## 2. Wrong workaround
If users tried to roll out their own way of creating a read-only set, they would have to do something like `ImmutableHashSet<T>` or `FrozenSet`.

```csharp
var set = new HashSet<int> { 1, 2, 3 };
var readOnly = set.ToFrozenSet(); // Or ToImmutableHashSet()
```

While technically this is working, it has two major problems:
 1. Immutable collections like `ImmutableHashSet<T>` or `FrozenSet` need to copy the whole collection into its own memory to guarantee immutability. This can be a waste of memory and CPU cycles.
 2. It's not really readonly. Readonly and immutable are two different concepts. Readonly means you can't modify it, but you can still modify the original collection, which then would be reflected in the "readonly" collection. With immutable collections, this wouldn't be reflected. I even have a whole blog post about it: [*"ReadOnlyCollection is not an immutable collection"*](https://steven-giesel.com/blogPost/c20eb758-a611-4f98-9ddf-b9e2b83fcac9/readonlycollection-is-not-an-immutable-collection).

And that is why we have `ReadOnlySet<T>` now. If you want to dive deeper, check out the API Propsal: https://github.com/dotnet/runtime/issues/100113