System.Collections.ObjectModel.KeyedCollection is an interesting class, but with one drawback: it serializes in XNA's IntermediateSerializer, but doesn't deserialize. There're ways to write a custom serializer for this class, but I chose a little bit different route - making my own that doesn't need a custom serializer.
Advantages
- Different methods can be exposed between the pipeline and runtime versions. This can help make the collection immutable if desired.
- Hides methods that may not be needed at runtime like adding and removing elements.
- Provides regular for loop access for speed.
Disadvantages
- Extra complexity of a new class
- Have to re-implement any methods
Code
This is an abstract base class that serves solely as a container, provides an iterator, and a method of accessing by key.
abstract class KeyedCollection<T> : IEnumerable<T>
{
#region Internal Data
[ContentSerializer]
private List<T> _collection;
/// <summary>
/// Keyed lookup: <Key, Collection Index>
/// </summary>
[ContentSerializer]
private Dictionary<int, int> _lookup;
#endregion;
#region Properties
/// <summary>
/// Indexer
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
[ContentSerializerIgnore]
public T this[int index]
{
get
{
return _collection[_lookup[index]];
}
}
/// <summary>
/// Number of elements in the collection
/// </summary>
[ContentSerializerIgnore]
public int Count
{
get
{
return _collection.Count;
}
}
#endregion;
/// <summary>
/// Constructor
/// </summary>
public KeyedCollection()
{
_collection = new List<T>();
_lookup = new Dictionary<int, int>();
}
/// <summary>
/// Find the neighbor at the given keyed index.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T Key(int index)
{
return _collection[_lookup[index]];
}
#region IEnumerable
/// <summary>
/// Enumerator
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
foreach (T element in _collection)
{
yield return element;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion;
}
Pipeline compiler directives already included too! It's a bit sparse for now, but a start.