ReadOnlyCollections
Remarks#
A ReadOnlyCollection
provides a read-only view to an existing collection (the ‘source collection’).
Items are not directly added to or removed from a ReadOnlyCollection
. Instead, they are added and removed from the source collection and the ReadOnlyCollection
will reflect these changes to the source.
The number and order of elements inside a ReadOnlyCollection
cannot be modified, but the properties of the elements can be and the methods can be called, assuming they are in scope.
Use a ReadOnlyCollection
when you want to allow external code to view your collection without being able to modify it, but still be able to modify the collection yourself.
See Also
ObservableCollection<T>
ReadOnlyObservableCollection<T>
ReadOnlyCollections vs ImmutableCollection
A ReadOnlyCollection
differs from an ImmutableCollection
in that you cannot edit an ImmutableCollection
once you created it - it will always contain n
elements, and they cannot be replaced or reordered. A ReadOnlyCollection
, on the other hand, cannot be edited directly, but elements can still be added/removed/reordered using the source collection.
Creating a ReadOnlyCollection
Using the Constructor
A ReadOnlyCollection
is created by passing an existing IList
object into the constructor:
var groceryList = new List<string> { "Apple", "Banana" };
var readOnlyGroceryList = new ReadOnlyCollection<string>(groceryList);
Using LINQ
Additionaly, LINQ provides an AsReadOnly()
extension method for IList
objects:
var readOnlyVersion = groceryList.AsReadOnly();
Note
Typically, you want to maintain the source collection privately and allow public access to the ReadOnlyCollection
. While you could create a ReadOnlyCollection
from an in-line list, you would be unable to modify the collection after you created it.
var readOnlyGroceryList = new List<string> {"Apple", "Banana"}.AsReadOnly();
// Great, but you will not be able to update the grocery list because
// you do not have a reference to the source list anymore!
If you find yourself doing this, you may want to consider using another data structure, such as an ImmutableCollection
.
Updating a ReadOnlyCollection
A ReadOnlyCollection
cannot be edited directly. Instead, the source collection is updated and the ReadOnlyCollection
will reflect these changes. This is the key feature of the ReadOnlyCollection
.
var groceryList = new List<string> { "Apple", "Banana" };
var readOnlyGroceryList = new ReadOnlyCollection<string>(groceryList);
var itemCount = readOnlyGroceryList.Count; // There are currently 2 items
//readOnlyGroceryList.Add("Candy"); // Compiler Error - Items cannot be added to a ReadOnlyCollection object
groceryList.Add("Vitamins"); // ..but they can be added to the original collection
itemCount = readOnlyGroceryList.Count; // Now there are 3 items
var lastItem = readOnlyGroceryList.Last(); // The last item on the read only list is now "Vitamins"
Warning: Elements in a ReadOnlyCollection are not inherently read-only
If the source collection is of a type that is not immutable, elements accessed through a ReadOnlyCollection
can be modified.
public class Item
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public static void FillOrder()
{
// An order is generated
var order = new List<Item>
{
new Item { Name = "Apple", Price = 0.50m },
new Item { Name = "Banana", Price = 0.75m },
new Item { Name = "Vitamins", Price = 5.50m }
};
// The current sub total is $6.75
var subTotal = order.Sum(item => item.Price);
// Let the customer preview their order
var customerPreview = new ReadOnlyCollection<Item>(order);
// The customer can't add or remove items, but they can change
// the price of an item, even though it is a ReadOnlyCollection
customerPreview.Last().Price = 0.25m;
// The sub total is now only $1.50!
subTotal = order.Sum(item => item.Price);
}