Click here to Skip to main content
Click here to Skip to main content
Go to top

Immutable Generic Collection Extensions

, 18 Dec 2007
Rate this:
Please Sign up or sign in to vote.
Create immutable / read-only collections from existing ICollection, IList, or IDictionary instances.

Introduction

The System.Collections.Generic classes enable you to easily create typed data structures. However, it is missing generic classes that allow you to create immutable / readonly collection instances. In this article, I'll describe how to easily create an immutable collection from an existing generic instance, using C# 3.0 extension methods.

Background

Immutable collections are instances of collection classes whose contents cannot be modified. Immutability is required in certain programming scenarios where the contents of the collection must be static to ensure that it can be "safely" used by any consumer without modifying the state of the program.

Generic collection classes were introduced in the .NET framework 2.0 System.Collections.Generic namespace. The generic collection classes enabled developers to easily create typed collections, whereas in .NET 1.x, you either had to use untyped collections or create a custom collection with typed methods.

Unfortunately, for most generic collections, .NET 2.0 does not contain corresponding immutable generic classes or methods. For example, if you create a typed System.Collections.Generic.List<T>, then the List.Add<T>( T typedObject ) method is automatically created and cannot be overridden.

As a solution, it is possible to create a custom version of a generic collection interface which creates a facade for an existing mutable instance. The facade class can implement the same collection interface as the class it wraps, but will throw an exception when any of its mutator methods are called. The facade class can then be used like so:

using System.Collections.Generic;
using Com.WickedByte.Collections.Generic;

IList<string> mutable = new List<string>();
mutable.Add( "Hello " );

// public class ImmutableList<T> : IList<T>{...}
IList<string> readOnly = new ImmutableList<string>( mutable );

//By design, the next call throws an exception.
readOnly.Add( "World!" );

This approach works, but is rather unwieldy, because it requires developers to be familiar with each of the custom immutable classes that you create.

Fortunately, C# 3.0 introduces an elegant way to solve this problem by introducing extension methods. Extension methods allow you to add methods to any existing class without modifying the source of the existing class. In the C# 3.0 approach, I've created immutable wrapper classes that implement ICollection<T>, IList<T>, and IDictionary<TKey,TValue>. However, I've made their visibility internal, so that developers are not aware of the custom implementations. Instead of publically exposing the custom classes, I've created an extension method for each collection interface, called ToReadOnly(). Developers need only to import the correct namespace, and will then be able to create an immutable instance with a single method call on the existing mutable generic instance.

Using the code

To use the code, import the Com.WickedByte.Collections.Generic namespace, and then call ToReadOnly() on any instance of ICollection<T>, IList<T>, or IDictionary<TKey,TValue>.

using Com.WickedByte.Collections.Generic;
using System.Collections.Generic;

IList<string> helloWorld = new List<string>();
helloWorld.Add( "Hello " );
IList<string> justHello = helloWorld.ToReadOnly();

//throws ReadOnlyException
justHello.Add( "World!" );

It's important to note that if you retain a reference to the original mutable collection instance, then the immutable collection can still be modified indirectly.

I've only created extension methods for the three main collection interfaces: ICollection<T>, IList<T>, and IDictionary<TKey,TValue>. You may wish to create your own extension methods for classes such as Stack<T> or HashSet<T>. When designing your facade class, it's important to notice whether any of the interface methods or properties return another collection. To preserve the integrity of the parent class, the returned collection must also be immutable. For example, in designing the immutable version of IDictionary<TKey,TValue>, I noted that both the Keys and Values properties returned an ICollection<T>. I simply returned an instance of my custom immutable ICollection<T> for each of these properties.

History

  • Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Marshall Rosenstein
Software Developer (Senior) WickedByte Software
United States United States
Marshall's torrid relationship with programming started as a child using BASIC on a Commodore PET computer in the 70's. He continued programming through high school, but did not study Computer Science in college. At the time, compilers would fail without telling you why, so after much soul searching, he realized he didn't want to make a living by spending eight hours a day looking for a missing semi-colon.
 
By the time he was pursuing his Ph.D. in Communication and Marketing, Microsoft had released Visual Studio. The improvements in the IDE were enough to cause Marshall to have late night affairs with COM and ASP. Marshall spent the dotcom bubble years as a web developer. After the bubble burst, he worked independently as a Java developer for medical applications. When Microsoft released an early beta of the .NET Framework, he was convinced to switch his focus from the Java Platform to the new Framework. He spent some time at Philips Medical Systems writing the data-access layer for the Carevue Chart hospital system. He is currently Technical Director for ASE Technologies.
 
Marshall lives in Salem, Massachusetts but would rather be in Hawaii.

Comments and Discussions

 
QuestionDesign [modified] PinmemberAndrew Shapira5-May-08 18:20 
This area is very difficult.
 
My first reaction is that the solution in this article (assuming it works) seems to be pretty good, given the existing design of the generic collections. It solves this problem: how can an owner of an instance X cleanly and efficiently present X to clients in such a way that clients can use X usefully, while not allowing clients to initiate mutations to X?
 
I also think that something is wrong when the number of classes must be doubled to support immutability. Supporting immutability for previously existing types without modifying the types, as in this case, might require doubling the number of classes. But in general, I think that the application type system is not the right place to differentiate mutable instances from immutable ones.
 
Clearly you have ideas about mutability in C# - how if at all, you would have designed List differently from scratch to support immutability, and what kind of immutability should be supported?
 
modified on Tuesday, May 6, 2008 4:34 PM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 18 Dec 2007
Article Copyright 2007 by Marshall Rosenstein
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid