One of the considerations you will face when writing an application is how to make sure that the state within your class is protected, in terms of external access and modification.

For example, this is a problematic design:

public class Spy
{
	public string FirstName { get; set; }
	public string Surname { get; set; }
}

It is problematic because a developer can do this:

var spy = new Spy { FirstName = "James", Surname = "Bond" };

spy.FirstName = "Jane";

This is likely not what you want.

You can address this issue as follows:

public class Spy
{
	public required string FirstName { get; init; }
	public required string Surname { get; init; }
}

Now you cannot change the internal state of the type.

What if the property you want to expose is a collection?

You would typically start by doing something like this:

public required string FirstName { get; init; }
public required string Surname { get; init; }
public List<string> Agencies { get; } = [];

You can then add an Agency as follows:

var spy = new Spy { FirstName = "James", Surname = "Bond" };
spy.Agencies.Add("MI-6");
spy.Agencies.Add("MI-5");

The problem with doing it this way is that if you are exposing this to external users, they can do anything with your collection. Including this:

spy.Agencies.Clear();

Which might not be what you want.

A typical solution would be:

  1. Add dedicated logic to add an Agency that populates an internal Agency collection.

  2. Expose the Agency collection using a read-only collection.

public sealed class Spy
{
    private readonly List<string> _agencies = [];
    public IEnumerable<string> Agencies => _agencies.AsReadOnly();
    public required string FirstName { get; init; }
    public required string Surname { get; init; }


    public void AddAgency(string agency)
    {
        if (!_agencies.Contains(agency))
            _agencies.Add(agency);
    }
}

Users can then do the following:

var spy = new Spy { FirstName = "James", Surname = "Bond" };

spy.AddAgency("MI-5");
spy.AddAgency("MI-6");

Console.WriteLine($"{spy.FirstName} {spy.Surname} is in  {spy.Agencies.Count()}");

So far, so good.

Suppose we had a property Stations that looked like this:

public string[] Stations = ["London", "Barbados", "Jamaica"];

You cannot expose this directly as it could be changed.

A client could do this:

spy.Stations[0] = "Nairobi";

The typical solution would be to do this:

private readonly string[] _stations = ["London", "Barbados", "Jamaica"];
public IEnumerable<string> Stations => _stations.AsReadOnly();

This IEnumerable would be, just like before, a ReadOnlyCollection of string.

This collection cannot be modified - you cannot modify the elements themselves or add to them, or clear them.

Thus, your internal state cannot be interfered with from outside, unless you explicitly provide contracts to do this.

TLDR

When exposing collections from a type, consider using a ReadOnlyCollection to prevent inadvertent or deliberate manipulation of your collection.

The code is in my GitHub.

Happy hacking!