示例#1
0
        /// <summary>
        /// Provides the actual implementation for deserializing a value of type <see cref="!:T" />.
        /// </summary>
        /// <param name="value">The uninitialized value to serialize into. This value will have been created earlier using <see cref="M:OdinSerializer.BaseFormatter`1.GetUninitializedObject" />.</param>
        /// <param name="reader">The reader to deserialize with.</param>
        protected override void DeserializeImplementation(ref T value, IDataReader reader)
        {
            string    name;
            EntryType entry;

            entry = reader.PeekEntry(out name);

            if (entry == EntryType.StartOfArray)
            {
                // We have legacy ISerializable data for the MethodInfo, since in no case will data written by this formatter ever start with an array.
                // In this case, get the proper legacy formatter for this type and read the data using that.

                IFormatter <T> serializableFormatter;

                try
                {
                    serializableFormatter = (IFormatter <T>)Activator.CreateInstance(typeof(SerializableFormatter <>).MakeGenericType(typeof(T)));
                }
                catch (Exception)
                {
                    reader.Context.Config.DebugContext.LogWarning("MethodInfo with legacy ISerializable data serialized was read in a context where a SerializableFormatter<T> formatter for the type could not be instantiated, likely in an IL2CPP build. This means legacy data cannot be read properly - please reserialize all data in your project to ensure no legacy MethodInfo data is included in your build, as this case is not AOT-supported by default.");

                    value = null;
                    return;
                }

                value = serializableFormatter.Deserialize(reader);
                return;
            }

            Type   declaringType = null;
            string methodName    = null;

            Type[] signature        = null;
            Type[] genericArguments = null;

            while ((entry = reader.PeekEntry(out name)) != EntryType.EndOfNode && entry != EntryType.EndOfArray && entry != EntryType.EndOfStream)
            {
                switch (name)
                {
                case "declaringType":
                {
                    var t = TypeSerializer.ReadValue(reader);

                    if (t != null)
                    {
                        declaringType = t;
                    }
                }
                break;

                case "methodName":
                {
                    methodName = StringSerializer.ReadValue(reader);
                }
                break;

                case "signature":
                {
                    signature = TypeArraySerializer.ReadValue(reader);
                }
                break;

                case "genericArguments":
                {
                    genericArguments = TypeArraySerializer.ReadValue(reader);
                }
                break;

                default:
                    reader.SkipEntry();
                    break;
                }
            }

            if (declaringType == null)
            {
                reader.Context.Config.DebugContext.LogWarning("Missing declaring type of MethodInfo on deserialize.");
                return;
            }

            if (methodName == null)
            {
                reader.Context.Config.DebugContext.LogError("Missing method name of MethodInfo on deserialize.");
                return;
            }

            MethodInfo methodInfo;
            bool       useSignature = false;
            bool       wasAmbiguous = false;

            if (signature != null)
            {
                useSignature = true;

                for (int i = 0; i < signature.Length; i++)
                {
                    if (signature[i] == null)
                    {
                        useSignature = false;
                        break;
                    }
                }
            }

            if (useSignature)
            {
                try
                {
                    methodInfo = declaringType.GetMethod(methodName, Flags.AllMembers, null, signature, null);
                }
                catch (AmbiguousMatchException)
                {
                    methodInfo   = null;
                    wasAmbiguous = true;
                }
            }
            else
            {
                try
                {
                    methodInfo = declaringType.GetMethod(methodName, Flags.AllMembers);
                }
                catch (AmbiguousMatchException)
                {
                    methodInfo   = null;
                    wasAmbiguous = true;
                }
            }

            if (methodInfo == null)
            {
                if (useSignature)
                {
                    reader.Context.Config.DebugContext.LogWarning("Could not find method with signature " + name + "(" + string.Join(", ", signature.Select(p => p.GetNiceFullName()).ToArray()) + ") on type '" + declaringType.FullName + (wasAmbiguous ? "; resolution was ambiguous between multiple methods" : string.Empty) + ".");
                }
                else
                {
                    reader.Context.Config.DebugContext.LogWarning("Could not find method with name " + name + " on type '" + declaringType.GetNiceFullName() + (wasAmbiguous ? "; resolution was ambiguous between multiple methods" : string.Empty) + ".");
                }

                return;
            }

            if (methodInfo.IsGenericMethodDefinition)
            {
                if (genericArguments == null)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' to deserialize is a generic method definition, but no generic arguments were in the serialization data.");
                    return;
                }

                int argCount = methodInfo.GetGenericArguments().Length;

                if (genericArguments.Length != argCount)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' to deserialize is a generic method definition, but there is the wrong number of generic arguments in the serialization data.");
                    return;
                }

                for (int i = 0; i < genericArguments.Length; i++)
                {
                    if (genericArguments[i] == null)
                    {
                        reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' to deserialize is a generic method definition, but one of the serialized generic argument types failed to bind on deserialization.");
                        return;
                    }
                }

                try
                {
                    methodInfo = methodInfo.MakeGenericMethod(genericArguments);
                }
                catch (Exception ex)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' to deserialize is a generic method definition, but failed to create generic method from definition, using generic arguments '" + string.Join(", ", genericArguments.Select(p => p.GetNiceFullName()).ToArray()) + "'. Method creation failed with an exception of type " + ex.GetType().GetNiceFullName() + ", with the message: " + ex.Message);
                    return;
                }
            }

            try
            {
                value = (T)methodInfo;
            }
            catch (InvalidCastException)
            {
                reader.Context.Config.DebugContext.LogWarning("The serialized method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' was successfully resolved into a MethodInfo reference of the runtime type '" + methodInfo.GetType().GetNiceFullName() + "', but failed to be cast to expected type '" + typeof(T).GetNiceFullName() + "'.");
                return;
            }

            this.RegisterReferenceID(value, reader);
        }
示例#2
0
 /// <summary>
 /// Reads into the specified value using the specified reader.
 /// </summary>
 /// <param name="value">The value to read into.</param>
 /// <param name="reader">The reader to use.</param>
 protected override void Read(ref Bounds value, IDataReader reader)
 {
     value.center = Vector3Serializer.ReadValue(reader);
     value.size   = Vector3Serializer.ReadValue(reader);
 }
示例#3
0
        /// <summary>
        /// Provides the actual implementation for deserializing a value of type <see cref="!:T" />.
        /// </summary>
        /// <param name="value">The uninitialized value to serialize into. This value will have been created earlier using <see cref="M:OdinSerializer.BaseFormatter`1.GetUninitializedObject" />.</param>
        /// <param name="reader">The reader to deserialize with.</param>
        protected override void DeserializeImplementation(ref T value, IDataReader reader)
        {
            string    name;
            EntryType entry;

            Type   delegateType  = typeof(T);
            Type   declaringType = null;
            object target        = null;
            string methodName    = null;

            Type[]     signature        = null;
            Type[]     genericArguments = null;
            Delegate[] invocationList   = null;

            while ((entry = reader.PeekEntry(out name)) != EntryType.EndOfNode && entry != EntryType.EndOfArray && entry != EntryType.EndOfStream)
            {
                switch (name)
                {
                case "invocationList":
                {
                    invocationList = DelegateArraySerializer.ReadValue(reader);
                }
                break;

                case "target":
                {
                    target = ObjectSerializer.ReadValue(reader);
                }
                break;

                case "declaringType":
                {
                    var t = TypeSerializer.ReadValue(reader);

                    if (t != null)
                    {
                        declaringType = t;
                    }
                }
                break;

                case "methodName":
                {
                    methodName = StringSerializer.ReadValue(reader);
                }
                break;

                case "delegateType":
                {
                    var t = TypeSerializer.ReadValue(reader);

                    if (t != null)
                    {
                        delegateType = t;
                    }
                }
                break;

                case "signature":
                {
                    signature = TypeArraySerializer.ReadValue(reader);
                }
                break;

                case "genericArguments":
                {
                    genericArguments = TypeArraySerializer.ReadValue(reader);
                }
                break;

                default:
                    reader.SkipEntry();
                    break;
                }
            }

            if (invocationList != null)
            {
                Delegate combinedDelegate = null;

                try
                {
                    combinedDelegate = Delegate.Combine(invocationList);
                }
                catch (Exception ex)
                {
                    reader.Context.Config.DebugContext.LogError("Recombining delegate invocation list upon deserialization failed with an exception of type " + ex.GetType().GetNiceFullName() + " with the message: " + ex.Message);
                }

                if (combinedDelegate != null)
                {
                    try
                    {
                        value = (T)(object)combinedDelegate;
                    }
                    catch (InvalidCastException)
                    {
                        reader.Context.Config.DebugContext.LogWarning("Could not cast recombined delegate of type " + combinedDelegate.GetType().GetNiceFullName() + " to expected delegate type " + typeof(T).GetNiceFullName() + ".");
                    }
                }

                return;
            }

            if (declaringType == null)
            {
                reader.Context.Config.DebugContext.LogWarning("Missing declaring type of delegate on deserialize.");
                return;
            }

            if (methodName == null)
            {
                reader.Context.Config.DebugContext.LogError("Missing method name of delegate on deserialize.");
                return;
            }

            MethodInfo methodInfo;
            bool       useSignature = false;
            bool       wasAmbiguous = false;

            if (signature != null)
            {
                useSignature = true;

                for (int i = 0; i < signature.Length; i++)
                {
                    if (signature[i] == null)
                    {
                        useSignature = false;
                        break;
                    }
                }
            }

            if (useSignature)
            {
                try
                {
                    methodInfo = declaringType.GetMethod(methodName, Flags.AllMembers, null, signature, null);
                }
                catch (AmbiguousMatchException)
                {
                    methodInfo   = null;
                    wasAmbiguous = true;
                }
            }
            else
            {
                try
                {
                    methodInfo = declaringType.GetMethod(methodName, Flags.AllMembers);
                }
                catch (AmbiguousMatchException)
                {
                    methodInfo   = null;
                    wasAmbiguous = true;
                }
            }

            if (methodInfo == null)
            {
                if (useSignature)
                {
                    reader.Context.Config.DebugContext.LogWarning("Could not find method with signature " + name + "(" + string.Join(", ", signature.Select(p => p.GetNiceFullName()).ToArray()) + ") on type '" + declaringType.FullName + (wasAmbiguous ? "; resolution was ambiguous between multiple methods" : string.Empty) + ".");
                }
                else
                {
                    reader.Context.Config.DebugContext.LogWarning("Could not find method with name " + name + " on type '" + declaringType.GetNiceFullName() + (wasAmbiguous ? "; resolution was ambiguous between multiple methods" : string.Empty) + ".");
                }

                return;
            }

            if (methodInfo.IsGenericMethodDefinition)
            {
                if (genericArguments == null)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is a generic method definition, but no generic arguments were in the serialization data.");
                    return;
                }

                int argCount = methodInfo.GetGenericArguments().Length;

                if (genericArguments.Length != argCount)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is a generic method definition, but there is the wrong number of generic arguments in the serialization data.");
                    return;
                }

                for (int i = 0; i < genericArguments.Length; i++)
                {
                    if (genericArguments[i] == null)
                    {
                        reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is a generic method definition, but one of the serialized generic argument types failed to bind on deserialization.");
                        return;
                    }
                }

                try
                {
                    methodInfo = methodInfo.MakeGenericMethod(genericArguments);
                }
                catch (Exception ex)
                {
                    reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is a generic method definition, but failed to create generic method from definition, using generic arguments '" + string.Join(", ", genericArguments.Select(p => p.GetNiceFullName()).ToArray()) + "'. Method creation failed with an exception of type " + ex.GetType().GetNiceFullName() + ", with the message: " + ex.Message);
                    return;
                }
            }

            if (methodInfo.IsStatic)
            {
                value = (T)(object)Delegate.CreateDelegate(delegateType, methodInfo, false);
            }
            else
            {
                Type targetType = methodInfo.DeclaringType;

                if (typeof(UnityEngine.Object).IsAssignableFrom(targetType))
                {
                    if ((target as UnityEngine.Object) == null)
                    {
                        reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is an instance method, but Unity object target of type '" + targetType.GetNiceFullName() + "' was null on deserialization. Did something destroy it, or did you apply a delegate value targeting a scene-based UnityEngine.Object instance to a prefab?");
                        return;
                    }
                }
                else
                {
                    if (object.ReferenceEquals(target, null))
                    {
                        reader.Context.Config.DebugContext.LogWarning("Method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "' of delegate to deserialize is an instance method, but no valid instance target of type '" + targetType.GetNiceFullName() + "' was in the serialization data. Has something been renamed since serialization?");
                        return;
                    }
                }

                value = (T)(object)Delegate.CreateDelegate(delegateType, target, methodInfo, false);
            }

            if (value == null)
            {
                reader.Context.Config.DebugContext.LogWarning("Failed to create delegate of type " + delegateType.GetNiceFullName() + " from method '" + declaringType.GetNiceFullName() + "." + methodInfo.GetNiceName() + "'.");
                return;
            }

            this.RegisterReferenceID(value, reader);
            this.InvokeOnDeserializingCallbacks(ref value, reader.Context);
        }
        /// <summary>
        /// Provides the actual implementation for deserializing a value of type <see cref="T" />.
        /// </summary>
        /// <param name="value">The uninitialized value to serialize into. This value will have been created earlier using <see cref="BaseFormatter{T}.GetUninitializedObject" />.</param>
        /// <param name="reader">The reader to deserialize with.</param>
        protected override void DeserializeImplementation(ref TDictionary value, IDataReader reader)
        {
            string name;
            var    entry = reader.PeekEntry(out name);

            IEqualityComparer <TKey> comparer = null;

            if (name == "comparer" || entry == EntryType.StartOfNode)
            {
                // There is a comparer serialized
                comparer = EqualityComparerSerializer.ReadValue(reader);
                entry    = reader.PeekEntry(out name);
            }

            if (entry == EntryType.StartOfArray)
            {
                try
                {
                    long length;
                    reader.EnterArray(out length);
                    Type type;

                    if (!object.ReferenceEquals(comparer, null) && ComparerConstructor != null)
                    {
                        value = (TDictionary)ComparerConstructor.Invoke(new object[] { comparer });
                    }
                    else
                    {
                        value = new TDictionary();
                    }

                    // We must remember to register the dictionary reference ourselves, since we returned null in GetUninitializedObject
                    this.RegisterReferenceID(value, reader);

                    // There aren't any OnDeserializing callbacks on dictionaries that we're interested in.
                    // Hence we don't invoke this.InvokeOnDeserializingCallbacks(value, reader, context);
                    for (int i = 0; i < length; i++)
                    {
                        if (reader.PeekEntry(out name) == EntryType.EndOfArray)
                        {
                            reader.Context.Config.DebugContext.LogError("Reached end of array after " + i + " elements, when " + length + " elements were expected.");
                            break;
                        }

                        bool exitNode = true;

                        try
                        {
                            reader.EnterNode(out type);
                            TKey   key = KeyReaderWriter.ReadValue(reader);
                            TValue val = ValueReaderWriter.ReadValue(reader);

                            if (!KeyIsValueType && object.ReferenceEquals(key, null))
                            {
                                reader.Context.Config.DebugContext.LogWarning("Dictionary key of type '" + typeof(TKey).FullName + "' was null upon deserialization. A key has gone missing.");
                                continue;
                            }

                            value[key] = val;
                        }
                        catch (SerializationAbortException ex)
                        {
                            exitNode = false;
                            throw ex;
                        }
                        catch (Exception ex)
                        {
                            reader.Context.Config.DebugContext.LogException(ex);
                        }
                        finally
                        {
                            if (exitNode)
                            {
                                reader.ExitNode();
                            }
                        }

                        if (reader.IsInArrayNode == false)
                        {
                            reader.Context.Config.DebugContext.LogError("Reading array went wrong. Data dump: " + reader.GetDataDump());
                            break;
                        }
                    }
                }
                finally
                {
                    reader.ExitArray();
                }
            }
            else
            {
                reader.SkipEntry();
            }
        }
        /// <summary>
        /// Provides the actual implementation for deserializing a value of type <see cref="T" />.
        /// </summary>
        /// <param name="value">The uninitialized value to serialize into. This value will have been created earlier using <see cref="BaseFormatter{T}.GetUninitializedObject" />.</param>
        /// <param name="reader">The reader to deserialize with.</param>
        protected override void DeserializeImplementation(ref TArray value, IDataReader reader)
        {
            string name;
            var    entry = reader.PeekEntry(out name);

            if (entry == EntryType.StartOfArray)
            {
                long length;
                reader.EnterArray(out length);

                entry = reader.PeekEntry(out name);

                if (entry != EntryType.String || name != RANKS_NAME)
                {
                    value = default(TArray);
                    reader.SkipEntry();
                    return;
                }

                string lengthStr;
                reader.ReadString(out lengthStr);

                string[] lengthsStrs = lengthStr.Split(RANKS_SEPARATOR);

                if (lengthsStrs.Length != ArrayRank)
                {
                    value = default(TArray);
                    reader.SkipEntry();
                    return;
                }

                int[] lengths = new int[lengthsStrs.Length];

                for (int i = 0; i < lengthsStrs.Length; i++)
                {
                    int rankVal;
                    if (int.TryParse(lengthsStrs[i], out rankVal))
                    {
                        lengths[i] = rankVal;
                    }
                    else
                    {
                        value = default(TArray);
                        reader.SkipEntry();
                        return;
                    }
                }

                long rankTotal = lengths[0];

                for (int i = 1; i < lengths.Length; i++)
                {
                    rankTotal *= lengths[i];
                }

                if (rankTotal != length)
                {
                    value = default(TArray);
                    reader.SkipEntry();
                    return;
                }

                value = (TArray)(object)Array.CreateInstance(typeof(TElement), lengths);

                // We must remember to register the array reference ourselves, since we return null in GetUninitializedObject
                this.RegisterReferenceID(value, reader);

                // There aren't any OnDeserializing callbacks on arrays.
                // Hence we don't invoke this.InvokeOnDeserializingCallbacks(value, reader, context);
                int elements = 0;

                try
                {
                    this.IterateArrayWrite(
                        (Array)(object)value,
                        () =>
                    {
                        if (reader.PeekEntry(out name) == EntryType.EndOfArray)
                        {
                            reader.Context.Config.DebugContext.LogError("Reached end of array after " + elements + " elements, when " + length + " elements were expected.");
                            throw new InvalidOperationException();
                        }

                        var v = ValueReaderWriter.ReadValue(reader);

                        if (reader.IsInArrayNode == false)
                        {
                            reader.Context.Config.DebugContext.LogError("Reading array went wrong. Data dump: " + reader.GetDataDump());
                            throw new InvalidOperationException();
                        }

                        elements++;
                        return(v);
                    });
                }
                catch (InvalidOperationException)
                {
                }
                catch (Exception ex)
                {
                    reader.Context.Config.DebugContext.LogException(ex);
                }

                reader.ExitArray();
            }
            else
            {
                value = default(TArray);
                reader.SkipEntry();
            }
        }