Collections & LINQ · Lesson 31

Read-only views and stable snapshots

Distinguish restricted access from independently frozen collection contents.

How it works

A read-only collection interface limits what a caller can request through that interface. It does not necessarily make the underlying collection immutable. Another owner can still mutate a list that backs a read-only view. This distinction matters when a report, cached result, or user interface expects its input to remain stable during later processing.

A snapshot requires a separate ownership decision. Copying the elements into a new array creates a new container, while exposing the existing list through a read-only interface only restricts that access path. Even a copied container is shallow when its elements are mutable references. Name APIs according to the guarantee they actually provide: view, copy, and immutable value describe different contracts.

Walk through the example. The source list contains two labels. An IReadOnlyList variable refers to that same list, while ToArray creates a separate snapshot. Adding a third label through the original list increases the view's Count to three. The snapshot still contains two elements and prints only the original labels. No mutation is attempted through the read-only interface itself.

Watch the boundary. Returning IReadOnlyList does not prevent a caller from discovering a concrete mutable type in some designs, and it does not prevent another existing owner from changing the data. Do not claim deep immutability based only on an interface type. Conversely, copying every collection automatically can be wasteful when a live read-only view is the intended behavior. State the lifetime and ownership expectations explicitly.

Practice independently. Create a report-building function that must retain the labels exactly as they were when called. Implement it first with a view and then with a snapshot, mutate the source, and compare the results. Repeat with a mutable object as the element type. Explain what additional copying or immutable modeling would be required if later property changes must also be excluded from the report.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

var source = new List<string> { "draft", "review" };
IReadOnlyList<string> view = source;
string[] snapshot = source.ToArray();
source.Add("publish");
Console.WriteLine(view.Count);
Console.WriteLine(snapshot.Length);
Console.WriteLine(string.Join(",", snapshot));

Expected output

3
2
draft,review
Try this
A read-only view can still change through its owner; a container snapshot needs a copy.