Thanks for your answers, Iwa and hiddenspring81.
I also needed to serialize a dictionary, but I generally don’t like using parallel sets of information, so I made my own version of the same concept that uses a custom KeyValuePair class to keep both bits of information together. It implements the IDictionary interface for a little extra versatility.
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public abstract class SerializedKeyValuePair<TKey, TValue>
where TKey : IEquatable<TKey>
{
public abstract TKey Key { get; set; }
public abstract TValue Value { get; set; }
public SerializedKeyValuePair(TKey key, TValue value)
{
Key = key;
Value = value;
}
public KeyValuePair<TKey, TValue> AsKeyValuePair()
{
return new KeyValuePair<TKey, TValue> (Key, Value);
}
}
public abstract class SerializedDictionary<TKeyValuePair, TKey, TValue> :
IDictionary<TKey, TValue>
where TKeyValuePair : SerializedKeyValuePair<TKey, TValue>
where TKey : IEquatable<TKey>
{
protected abstract List<TKeyValuePair> KeyValuePairs { get; }
public abstract void Add (TKey key, TValue value);
public bool ContainsKey (TKey key)
{
foreach (TKeyValuePair kvp in KeyValuePairs)
{
if (kvp.Key.Equals(key))
{
return true;
}
}
return false;
}
public bool ContainsValue(TValue value)
{
EqualityComparer<TValue> equalityComparer = EqualityComparer<TValue>.Default;
foreach (TKeyValuePair kvp in KeyValuePairs)
{
if (equalityComparer.Equals(kvp.Value, value))
{
return true;
}
}
return false;
}
public bool Remove (TKey key)
{
for (int i = 0; i < KeyValuePairs.Count; i++)
{
TKeyValuePair kvp = KeyValuePairs*;*
-
if (kvp.Key.Equals(key))*
-
{*
-
KeyValuePairs.RemoveAt(i);*
-
return true;*
-
}*
-
}*
-
return false;*
-
}*
-
public bool TryGetValue (TKey key, out TValue value)*
-
{*
-
foreach (TKeyValuePair kvp in KeyValuePairs)*
-
{*
-
if (kvp.Key.Equals(key))*
-
{*
-
value = kvp.Value;*
-
return true;*
-
}*
-
}*
-
value = default(TValue);*
-
return false;*
-
}*
-
public TValue GetValue(TKey key)*
-
{*
-
foreach (TKeyValuePair kvp in KeyValuePairs)*
-
{*
-
if (kvp.Key.Equals(key))*
-
{*
-
return kvp.Value;*
-
}*
-
}*
-
throw new ArgumentException("No value was found for the given key");*
-
}*
-
public void Add (KeyValuePair<TKey, TValue> item)*
-
{*
-
Add (item.Key, item.Value);*
-
}*
-
public void Clear ()*
-
{*
-
KeyValuePairs.Clear ();*
-
}*
-
public bool Contains (KeyValuePair<TKey, TValue> item)*
-
{*
-
foreach (TKeyValuePair kvp in KeyValuePairs)*
-
{*
-
if (kvp.Key.Equals(item.Key))*
-
{*
-
return EqualityComparer<TValue>.Default.Equals(kvp.Value, item.Value);*
-
}*
-
}*
-
return false;*
-
}*
-
public void CopyTo (KeyValuePair<TKey, TValue> array, int arrayIndex)*
-
{*
-
for (int i = 0; i < KeyValuePairs.Count; i++)*
-
{*
_ TKeyValuePair kvp = KeyValuePairs*;_
_ array[i + arrayIndex] = new KeyValuePair<TKey, TValue>(kvp.Key, kvp.Value);_
_ }_
_ }*_
* public bool Remove (KeyValuePair<TKey, TValue> item)*
* {*
* if (Contains(item))*
* {*
* Remove(item.Key);*
* return true;*
* }*
* return false;*
* }*
* public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()*
* {*
* foreach(TKeyValuePair kvp in KeyValuePairs)*
* {*
* yield return new KeyValuePair<TKey, TValue>(kvp.Key, kvp.Value);*
* }*
* yield break;*
* }*
* IEnumerator IEnumerable.GetEnumerator ()*
* {*
* return GetEnumerator ();*
* }*
* public TValue this[TKey key]*
* {*
* get { return GetValue(key); }*
* set*
* {*
* for (int i = 0; i < KeyValuePairs.Count; i++)*
* {*
_ if (KeyValuePairs*.Key.Equals(key))
{
KeyValuePairs.Value = value;
return;
}
}*_
* Add(key, value);*
* }*
* }*
* public ICollection Keys {*
* get*
* {*
* List list = new List();*
* foreach (TKeyValuePair kvp in KeyValuePairs)*
* {*
* list.Add(kvp.Key);*
* }*
* return list;*
* }*
* }*
* public ICollection Values {*
* get*
* {*
* List list = new List();*
* foreach (TKeyValuePair kvp in KeyValuePairs)*
* {*
* list.Add(kvp.Value);*
* }*
* return list;*
* }*
* }*
* public int Count { get { return KeyValuePairs.Count; } }*
* public bool IsReadOnly { get { return false; } }*
* public Dictionary<TKey, TValue> ToDictionary()*
* {*
* Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue> ();*
* foreach (TKeyValuePair kvp in KeyValuePairs)*
* {*
* dictionary.Add(kvp.Key, kvp.Value);*
* }*
* return dictionary;*
* }*
}
Then, I had to create sub-classes for each, based on the information being serialized. In my case, the Key type was a struct, so leaving the serialization up to the sub-class was handy since Unity doesn’t serialize structs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using HexGame;
[System.Serializable]
public class MySerializedDictionary :
SerializedDictionary<MySerializedKeyValuePair, MyKey, MyValue>
{
* [SerializeField] private List m_keyValuePairs = new List();*
* protected override List KeyValuePairs*
* {*
* get { return m_keyValuePairs; }
_ }*_
* public override void Add (MyKey key, MyValue value)*
* {*
* if (ContainsKey(key))*
* {*
* throw new ArgumentException(“The dictionary already contains an entry with the specified key”);*
* }*
* else*
* {*
* KeyValuePairs.Add(new MySerializedKeyValuePair(key, value));*
* }*
* }*
}
[Serializable]
public class MySerializedKeyValuePair : SerializedKeyValuePair<MyKey, MyValue>
{
* [SerializeField] private int m_keyVariableA;
[SerializeField] private int m_keyVariableB;*
* [SerializeField] private MyValue m_value;*
* public override MyKey Key*
* {*
* get { return new MyKey(m_keyVariableA, m_keyVariableB); }
_ set*
* {_
m_keyVariableA = value.A;
m_keyVariableB = value.B;
_ }
}*_
* public override MyValue Value*
* {*
* get { return m_value; }
set { m_value = value; }
_ }*_
* public MySerializedKeyValuePair(MyKey key, MyValue value)*
* : base (key, value)*
* {}*
}