diff options
Diffstat (limited to 'Runtime/Export/Serialization/UnitySurrogateSelector.cs')
-rw-r--r-- | Runtime/Export/Serialization/UnitySurrogateSelector.cs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/Runtime/Export/Serialization/UnitySurrogateSelector.cs b/Runtime/Export/Serialization/UnitySurrogateSelector.cs new file mode 100644 index 0000000..17f09e4 --- /dev/null +++ b/Runtime/Export/Serialization/UnitySurrogateSelector.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace UnityEngine.Serialization +{ +#if !UNITY_WINRT + /// <summary> + /// Serialization support for <see cref="List{T}" /> and <see cref="Dictionary{TKey,TValue}" /> that doesn't rely on reflection + /// of private members in order to be useable under the CoreCLR security model (WebPlayer). + /// </summary> + public class UnitySurrogateSelector : ISurrogateSelector + { + public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector) + { + if (type.IsGenericType) + { + var genericTypeDefinition = type.GetGenericTypeDefinition(); + if (genericTypeDefinition == typeof(List<>)) + { + selector = this; + return ListSerializationSurrogate.Default; + } + if (genericTypeDefinition == typeof(Dictionary<,>)) + { + selector = this; + var dictSurrogateType = typeof(DictionarySerializationSurrogate<,>).MakeGenericType(type.GetGenericArguments()); + return (ISerializationSurrogate) Activator.CreateInstance(dictSurrogateType); + } + } + + selector = null; + return null; + } + + public void ChainSelector(ISurrogateSelector selector) + { + throw new NotImplementedException(); + } + + public ISurrogateSelector GetNextSelector() + { + throw new NotImplementedException(); + } + } + + /// <summary> + /// Serialization support for <see cref="List{T}" /> that doesn't rely on reflection of private members. + /// </summary> + class ListSerializationSurrogate : ISerializationSurrogate + { + public static readonly ISerializationSurrogate Default = new ListSerializationSurrogate(); + + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { + var list = (IList)obj; + info.AddValue("_size", list.Count); + info.AddValue("_items", ArrayFromGenericList(list)); + info.AddValue("_version", 0); // required for compatibility with platform deserialization + } + + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { + var list = (IList)Activator.CreateInstance(obj.GetType()); + var size = info.GetInt32("_size"); + if (size == 0) + return list; + + var items = ((IEnumerable)info.GetValue("_items", typeof(IEnumerable))).GetEnumerator(); + for (var i = 0; i < size; ++i) + { + if (!items.MoveNext()) + throw new InvalidOperationException(); + list.Add(items.Current); + } + return list; + } + + private static Array ArrayFromGenericList(IList list) + { + var items = Array.CreateInstance(list.GetType().GetGenericArguments()[0], list.Count); + list.CopyTo(items, 0); + return items; + } + } + + /// <summary> + /// Serialization support for <see cref="Dictionary{TKey,TValue}" /> that doesn't rely on non public members. + /// </summary> + class DictionarySerializationSurrogate<TKey, TValue> : ISerializationSurrogate + { + public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) + { + var dictionary = ((Dictionary<TKey, TValue>)obj); + dictionary.GetObjectData(info, context); + } + + public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) + { + var comparer = (IEqualityComparer<TKey>)info.GetValue("Comparer", typeof(IEqualityComparer<TKey>)); + var dictionary = new Dictionary<TKey, TValue>(comparer); + if (info.MemberCount > 3) // KeyValuePairs might not be present if the dictionary was empty + { + var keyValuePairs = + (KeyValuePair<TKey, TValue>[]) info.GetValue("KeyValuePairs", typeof(KeyValuePair<TKey, TValue>[])); + if (keyValuePairs != null) + foreach (var kvp in keyValuePairs) + dictionary.Add(kvp.Key, kvp.Value); + } + return dictionary; + } + } +#endif +} |