示例#1
0
        internal void WriteValueWithoutAdapters <TValue>(TValue value, bool isRoot)
        {
            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.WritePrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull && null == value)
            {
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsMultidimensionalArray)
            {
                // No support for multidimensional arrays yet. This can be done using adapters for now.
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                m_Stream->Add(k_TokenNone);

                var underlyingType = Nullable.GetUnderlyingType(typeof(TValue));

                if (RuntimeTypeInfoCache.IsContainerType(underlyingType))
                {
                    // IMPORTANT: Do NOT add a token to the stream since we are triggering a re-entrance on the same object here.
                    // Unpack Nullable<T> as T
                    var underlyingValue = Convert.ChangeType(value, underlyingType);

                    if (!PropertyContainer.TryAccept(this, ref underlyingValue, out var errorCode))
                    {
                        switch (errorCode)
                        {
                        case VisitErrorCode.NullContainer:
                            throw new ArgumentNullException(nameof(value));

                        case VisitErrorCode.InvalidContainerType:
                            throw new InvalidContainerTypeException(value.GetType());

                        case VisitErrorCode.MissingPropertyBag:
                            throw new MissingPropertyBagException(value.GetType());

                        default:
                            throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                        }
                    }
                }
                else
                {
                    BinarySerialization.WritePrimitiveBoxed(m_Stream, value, underlyingType);
                }

                return;
            }

            if (!RuntimeTypeInfoCache <TValue> .IsValueType)
            {
#if !UNITY_DOTSPLAYER
                if (!(isRoot && m_DisableRootAdapters) && value is UnityEngine.Object unityEngineObject)
                {
                    // Special path for polymorphic unity object references.
                    m_Stream->Add(k_TokenUnityEngineObjectReference);
                    (m_Adapters.Internal as Adapters.Contravariant.IBinaryAdapter <UnityEngine.Object>).Serialize(new BinarySerializationContext <TValue>(this, default, value, isRoot), unityEngineObject);
        void ReadValue <TValue>(ref TValue value, bool isRoot = false)
        {
            var runAdapters = !(isRoot && m_DisableRootAdapters);

            if (runAdapters && m_Adapters.TryDeserialize(m_Stream, ref value))
            {
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.ReadPrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            var token = default(byte);

            if (RuntimeTypeInfoCache <TValue> .CanBeNull)
            {
                token = m_Stream->ReadNext <byte>();

                switch (token)
                {
                case k_TokenNull:
                    value = default;
                    return;

                case k_TokenSerializedReference:
                    var id = m_Stream->ReadNext <int>();
                    if (null == m_SerializedReferences)
                    {
                        throw new Exception("Deserialization encountered a serialized object reference while running with DisableSerializedReferences.");
                    }
                    value = (TValue)m_SerializedReferences.GetDeserializedReference(id);
                    return;
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, Nullable.GetUnderlyingType(typeof(TValue)));
                return;
            }

#if !UNITY_DOTSPLAYER
            if (runAdapters && token == k_TokenUnityEngineObjectReference)
            {
                var unityEngineObject = default(UnityEngine.Object);
                m_Adapters.TryDeserialize(m_Stream, ref unityEngineObject);
                value = (TValue)(object)unityEngineObject;
                return;
            }
#endif

            if (token == k_TokenPolymorphic)
            {
                m_Stream->ReadNext(out var assemblyQualifiedTypeName);

                if (string.IsNullOrEmpty(assemblyQualifiedTypeName))
                {
                    throw new ArgumentException();
                }

                var concreteType = Type.GetType(assemblyQualifiedTypeName);

                if (null == concreteType)
                {
                    if (FormerNameAttribute.TryGetCurrentTypeName(assemblyQualifiedTypeName, out var currentAssemblyQualifiedTypeName))
                    {
                        concreteType = Type.GetType(currentAssemblyQualifiedTypeName);
                    }

                    if (null == concreteType)
                    {
                        throw new ArgumentException();
                    }
                }

                m_SerializedTypeProviderSerializedType = concreteType;
            }
            else
            {
                // If we have a user provided root type pass it to the type construction.
                m_SerializedTypeProviderSerializedType = isRoot ? m_SerializedType : null;
            }

            DefaultTypeConstruction.Construct(ref value, this);

            if (RuntimeTypeInfoCache <TValue> .IsObjectType && !RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, value.GetType());
                return;
            }

            if (!PropertyContainer.Visit(ref value, this, out var errorCode))
            {
                switch (errorCode)
                {
                case VisitErrorCode.NullContainer:
                    throw new ArgumentNullException(nameof(value));

                case VisitErrorCode.InvalidContainerType:
                    throw new InvalidContainerTypeException(value.GetType());

                case VisitErrorCode.MissingPropertyBag:
                    throw new MissingPropertyBagException(value.GetType());

                default:
                    throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                }
            }
        }
示例#3
0
        void WriteValue <TValue>(TValue value, bool isRoot = false)
        {
            var runAdapters = !(isRoot && m_DisableRootAdapters);

            if (runAdapters && m_Adapters.TrySerialize(m_Stream, ref value))
            {
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.WritePrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .CanBeNull && null == value)
            {
                m_Stream->Add(k_TokenNull);
                return;
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                m_Stream->Add(k_TokenNone);
                BinarySerialization.WritePrimitiveBoxed(m_Stream, value, Nullable.GetUnderlyingType(typeof(TValue)));
                return;
            }

            if (!RuntimeTypeInfoCache <TValue> .IsValueType)
            {
#if !UNITY_DOTSPLAYER
                if (runAdapters && value is UnityEngine.Object unityEngineObject)
                {
                    // Special path for polymorphic unity object references.
                    m_Stream->Add(k_TokenUnityEngineObjectReference);
                    m_Adapters.TrySerialize(m_Stream, ref unityEngineObject);
                    return;
                }
#endif

                if (null != m_SerializedReferences && !value.GetType().IsValueType)
                {
                    // At this point we don't know if an object will reference this value.
                    // To avoid a second visitation pass we always create an entry for each managed object reference.
                    var id = m_SerializedReferences.AddSerializedReference(value);

                    if (!m_SerializedReferences.SetSerialized(value))
                    {
                        // This is the second time encountering this object during serialization.
                        // We instead of writing out the object we simply write the id.
                        m_Stream->Add(k_TokenSerializedReference);
                        m_Stream->Add(id);
                        return;
                    }
                }

                // This is a very common case. At serialize time we are serializing something that is polymorphic or an object
                // However at deserialize time the user known the System.Type, we can avoid writing out the fully qualified type name in this case.
                var isRootAndTypeWasGiven = isRoot && null != m_SerializedType;

                if (typeof(TValue) != value.GetType() && !isRootAndTypeWasGiven)
                {
                    m_Stream->Add(k_TokenPolymorphic);
                    m_Stream->Add(value.GetType().AssemblyQualifiedName);
                }
                else
                {
                    m_Stream->Add(k_TokenNone);
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsObjectType && !RuntimeTypeInfoCache.IsContainerType(value.GetType()))
            {
                BinarySerialization.WritePrimitiveBoxed(m_Stream, value, value.GetType());
                return;
            }

            if (!PropertyContainer.Visit(ref value, this, out var errorCode))
            {
                switch (errorCode)
                {
                case VisitErrorCode.NullContainer:
                    throw new ArgumentNullException(nameof(value));

                case VisitErrorCode.InvalidContainerType:
                    throw new InvalidContainerTypeException(value.GetType());

                case VisitErrorCode.MissingPropertyBag:
                    throw new MissingPropertyBagException(value.GetType());

                default:
                    throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                }
            }
        }
        internal void ReadValueWithoutAdapters <TValue>(ref TValue value, bool isRoot)
        {
            if (RuntimeTypeInfoCache <TValue> .IsEnum)
            {
                BinarySerialization.ReadPrimitiveUnsafe(m_Stream, ref value, Enum.GetUnderlyingType(typeof(TValue)));
                return;
            }

            var token = default(byte);

            if (RuntimeTypeInfoCache <TValue> .CanBeNull)
            {
                token = m_Stream->ReadNext <byte>();

                switch (token)
                {
                case k_TokenNull:
                    value = default;
                    return;

                case k_TokenSerializedReference:
                    var id = m_Stream->ReadNext <int>();
                    if (null == m_SerializedReferences)
                    {
                        throw new Exception("Deserialization encountered a serialized object reference while running with DisableSerializedReferences.");
                    }
                    value = (TValue)m_SerializedReferences.GetDeserializedReference(id);
                    return;
                }
            }

            if (RuntimeTypeInfoCache <TValue> .IsNullable)
            {
                var underlyingType = Nullable.GetUnderlyingType(typeof(TValue));

                if (RuntimeTypeInfoCache.IsContainerType(underlyingType))
                {
                    m_SerializedTypeProviderSerializedType = underlyingType;
                    DefaultTypeConstruction.Construct(ref value, this);

                    var underlyingValue = Convert.ChangeType(value, underlyingType);

                    if (!PropertyContainer.TryAccept(this, ref underlyingValue, out var errorCode))
                    {
                        switch (errorCode)
                        {
                        case VisitErrorCode.NullContainer:
                            throw new ArgumentNullException(nameof(value));

                        case VisitErrorCode.InvalidContainerType:
                            throw new InvalidContainerTypeException(value.GetType());

                        case VisitErrorCode.MissingPropertyBag:
                            throw new MissingPropertyBagException(value.GetType());

                        default:
                            throw new Exception($"Unexpected {nameof(VisitErrorCode)}=[{errorCode}]");
                        }
                    }

                    // Repack the T as Nullable<T>
                    value = (TValue)underlyingValue;
                }
                else
                {
                    BinarySerialization.ReadPrimitiveBoxed(m_Stream, ref value, Nullable.GetUnderlyingType(typeof(TValue)));
                }
                return;
            }

#if !UNITY_DOTSPLAYER
            if (!(isRoot && m_DisableRootAdapters) && token == k_TokenUnityEngineObjectReference)
            {
                value = (TValue)(m_Adapters.Internal as Adapters.Contravariant.IBinaryAdapter <UnityEngine.Object>).Deserialize(new BinaryDeserializationContext <TValue>(this, default, isRoot));;