Further to Matt's answer, IList is a complete abstract interface to an array, so it allows add, remove, etc. I'm not sure why Lippert appears to suggest it as an alternative to IEnumerable where immutability is needed. (Edit: because the IList implementation can throw exceptions for those mutating methods, if you like that kind of thing).
Maybe another thing to bear in mind that the items on the list may also have mutable state. If you really don't want the caller to modify such state, you have some options:
Make sure the items on the list are immutable (as in your example: string is immutable).
Return a deep clone of everything, so in that case you could use an array anyway.
Return an interface that gives readonly access to an item:
interface IImmutable
{
public string ValuableCustomerData { get; }
}
class Mutable, IImmutable
{
public string ValuableCustomerData { get; set; }
}
public class Immy
{
private List<Mutable> _mutableList = new List<Mutable>();
public IEnumerable<IImmutable> ImmutableItems
{
get { return _mutableList.Cast<IMutable>(); }
}
}
Note that every value accessible from the IImmutable interface must itself be immutable (e.g. string), or else be a copy that you make on-the-fly.