using System; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization; namespace UnityEngine.Serialization { #if !UNITY_WINRT /// /// Serialization support for and that doesn't rely on reflection /// of private members in order to be useable under the CoreCLR security model (WebPlayer). /// 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(); } } /// /// Serialization support for that doesn't rely on reflection of private members. /// 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; } } /// /// Serialization support for that doesn't rely on non public members. /// class DictionarySerializationSurrogate : ISerializationSurrogate { public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { var dictionary = ((Dictionary)obj); dictionary.GetObjectData(info, context); } public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { var comparer = (IEqualityComparer)info.GetValue("Comparer", typeof(IEqualityComparer)); var dictionary = new Dictionary(comparer); if (info.MemberCount > 3) // KeyValuePairs might not be present if the dictionary was empty { var keyValuePairs = (KeyValuePair[]) info.GetValue("KeyValuePairs", typeof(KeyValuePair[])); if (keyValuePairs != null) foreach (var kvp in keyValuePairs) dictionary.Add(kvp.Key, kvp.Value); } return dictionary; } } #endif }