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.
Nice post, do you have the details of why the mighty IntermediateSerializer won't deserialize a KeyedCollection?
ReplyDeleteThanks
Just so you know, I just serialized and deserialized a KeyedCollection without any issues. What version of .NET/XNA were you using? it worked for me with 4.0
ReplyDeleteThis was way back with 3.1. Maybe in 4 they added serialization for this - I haven't checked. The class I wrote serves as a very simplified wrapper that only exposes a portion of the functionality. Mostly I was after immutability in my run-time classes.
ReplyDelete