Exemple #1
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}]");
                }
            }
        }