File: System\Runtime\Serialization\XmlObjectSerializerWriteContext.cs
Web Access
Project: src\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.DataContracts;
using System.Security;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
 
using ExtensionDataObject = System.Object;
 
namespace System.Runtime.Serialization
{
    internal class XmlObjectSerializerWriteContext : XmlObjectSerializerContext
    {
        private ObjectReferenceStack _byValObjectsInScope;
        private XmlSerializableWriter? _xmlSerializableWriter;
        private const int depthToCheckCyclicReference = 512;
        private ObjectToIdCache? _serializedObjects;
        private bool _isGetOnlyCollection;
        private readonly bool _unsafeTypeForwardingEnabled;
        protected bool serializeReadOnlyTypes;
        protected bool preserveObjectReferences;
 
        internal static XmlObjectSerializerWriteContext CreateContext(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver? dataContractResolver)
        {
            return (serializer.PreserveObjectReferences || serializer.SerializationSurrogateProvider != null)
                ? new XmlObjectSerializerWriteContextComplex(serializer, rootTypeDataContract, dataContractResolver)
                : new XmlObjectSerializerWriteContext(serializer, rootTypeDataContract, dataContractResolver);
        }
 
        protected XmlObjectSerializerWriteContext(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver? resolver)
            : base(serializer, rootTypeDataContract, resolver)
        {
            this.serializeReadOnlyTypes = serializer.SerializeReadOnlyTypes;
            // Known types restricts the set of types that can be deserialized
            _unsafeTypeForwardingEnabled = true;
        }
 
        internal XmlObjectSerializerWriteContext(XmlObjectSerializer serializer, int maxItemsInObjectGraph, StreamingContext streamingContext, bool ignoreExtensionDataObject)
            : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject)
        {
            // Known types restricts the set of types that can be deserialized
            _unsafeTypeForwardingEnabled = true;
        }
 
        protected ObjectToIdCache SerializedObjects => _serializedObjects ??= new ObjectToIdCache();
 
        internal override bool IsGetOnlyCollection
        {
            get { return _isGetOnlyCollection; }
            set { _isGetOnlyCollection = value; }
        }
 
        internal bool SerializeReadOnlyTypes
        {
            get { return this.serializeReadOnlyTypes; }
        }
 
        internal bool UnsafeTypeForwardingEnabled
        {
            get { return _unsafeTypeForwardingEnabled; }
        }
 
        internal void StoreIsGetOnlyCollection()
        {
            _isGetOnlyCollection = true;
        }
 
        internal void ResetIsGetOnlyCollection()
        {
            _isGetOnlyCollection = false;
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void InternalSerializeReference(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
        {
            if (!OnHandleReference(xmlWriter, obj, true /*canContainCyclicReference*/))
                InternalSerialize(xmlWriter, obj, isDeclaredType, writeXsiType, declaredTypeID, declaredTypeHandle);
            OnEndHandleReference(xmlWriter, obj, true /*canContainCyclicReference*/);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void InternalSerialize(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
        {
            if (writeXsiType)
            {
                Type declaredType = Globals.TypeOfObject;
                SerializeWithXsiType(xmlWriter, obj, obj.GetType().TypeHandle, null/*type*/, -1, declaredType.TypeHandle, declaredType);
            }
            else if (isDeclaredType)
            {
                DataContract contract = GetDataContract(declaredTypeID, declaredTypeHandle);
                SerializeWithoutXsiType(contract, xmlWriter, obj, declaredTypeHandle);
            }
            else
            {
                RuntimeTypeHandle objTypeHandle = obj.GetType().TypeHandle;
                if (declaredTypeHandle.GetHashCode() == objTypeHandle.GetHashCode()) // semantically the same as Value == Value; Value is not available in SL
                {
                    DataContract dataContract = (declaredTypeID >= 0)
                        ? GetDataContract(declaredTypeID, declaredTypeHandle)
                        : GetDataContract(declaredTypeHandle, null /*type*/);
                    SerializeWithoutXsiType(dataContract, xmlWriter, obj, declaredTypeHandle);
                }
                else
                {
                    SerializeWithXsiType(xmlWriter, obj, objTypeHandle, null /*type*/, declaredTypeID, declaredTypeHandle, Type.GetTypeFromHandle(declaredTypeHandle)!);
                }
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle)
        {
            if (OnHandleIsReference(xmlWriter, dataContract, obj))
                return;
            if (dataContract.KnownDataContracts?.Count > 0)
            {
                scopedKnownTypes.Push(dataContract.KnownDataContracts);
                WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle);
                scopedKnownTypes.Pop();
            }
            else
            {
                WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle);
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
        {
            Debug.Assert(rootTypeDataContract != null);
 
            bool verifyKnownType = false;
            Type declaredType = rootTypeDataContract.OriginalUnderlyingType;
 
            if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType))
            {
                if (DataContractResolver != null)
                {
                    WriteResolvedTypeInfo(xmlWriter, graphType, declaredType);
                }
            }
            else if (!declaredType.IsArray) //Array covariance is not supported in XSD. If declared type is array do not write xsi:type. Instead write xsi:type for each item
            {
                verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, rootTypeDataContract);
            }
            SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, originalDeclaredTypeHandle, declaredType);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        protected virtual void SerializeWithXsiType(XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle objectTypeHandle, Type? objectType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
        {
            bool verifyKnownType = false;
            DataContract dataContract;
            if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType))
            {
                dataContract = GetDataContractSkipValidation(DataContract.GetId(objectTypeHandle), objectTypeHandle, objectType);
                if (OnHandleIsReference(xmlWriter, dataContract, obj))
                    return;
                dataContract = GetDataContract(declaredTypeHandle, declaredType);
                if (!WriteClrTypeInfo(xmlWriter, dataContract) && DataContractResolver != null)
                {
                    objectType ??= Type.GetTypeFromHandle(objectTypeHandle)!;
                    WriteResolvedTypeInfo(xmlWriter, objectType, declaredType);
                }
            }
            else if (declaredType.IsArray)//Array covariance is not supported in XSD. If declared type is array do not write xsi:type. Instead write xsi:type for each item
            {
                // A call to OnHandleIsReference is not necessary here -- arrays cannot be IsReference
                dataContract = GetDataContract(objectTypeHandle, objectType);
                WriteClrTypeInfo(xmlWriter, dataContract);
                dataContract = GetDataContract(declaredTypeHandle, declaredType);
            }
            else
            {
                dataContract = GetDataContract(objectTypeHandle, objectType);
                if (OnHandleIsReference(xmlWriter, dataContract, obj))
                    return;
                if (!WriteClrTypeInfo(xmlWriter, dataContract))
                {
                    DataContract declaredTypeContract = (declaredTypeID >= 0)
                        ? GetDataContract(declaredTypeID, declaredTypeHandle)
                        : GetDataContract(declaredTypeHandle, declaredType);
                    verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, declaredTypeContract);
                }
            }
 
            SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, declaredTypeHandle, declaredType);
        }
 
        internal bool OnHandleIsReference(XmlWriterDelegator xmlWriter, DataContract contract, object obj)
        {
            if (preserveObjectReferences || !contract.IsReference || _isGetOnlyCollection)
            {
                return false;
            }
 
            bool isNew = true;
            int objectId = SerializedObjects.GetId(obj, ref isNew);
            _byValObjectsInScope.EnsureSetAsIsReference(obj);
            if (isNew)
            {
                xmlWriter.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.IdLocalName,
                                            DictionaryGlobals.SerializationNamespace, string.Create(CultureInfo.InvariantCulture, $"i{objectId}"));
                return false;
            }
            else
            {
                xmlWriter.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.RefLocalName, DictionaryGlobals.SerializationNamespace, string.Create(CultureInfo.InvariantCulture, $"i{objectId}"));
                return true;
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        protected void SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, bool verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
        {
            bool knownTypesAddedInCurrentScope = false;
            if (dataContract.KnownDataContracts?.Count > 0)
            {
                scopedKnownTypes.Push(dataContract.KnownDataContracts);
                knownTypesAddedInCurrentScope = true;
            }
 
            if (verifyKnownType)
            {
                if (!IsKnownType(dataContract, declaredType))
                {
                    DataContract? knownContract = ResolveDataContractFromKnownTypes(dataContract.XmlName.Name, dataContract.XmlName.Namespace, null /*memberTypeContract*/, declaredType);
                    if (knownContract == null || knownContract.UnderlyingType != dataContract.UnderlyingType)
                    {
                        throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.XmlName.Name, dataContract.XmlName.Namespace));
                    }
                }
            }
 
            WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle);
 
            if (knownTypesAddedInCurrentScope)
            {
                scopedKnownTypes.Pop();
            }
        }
 
        internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract)
        {
            return false;
        }
 
        internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, string clrTypeName, string clrAssemblyName)
        {
            return false;
        }
 
        internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, string? clrTypeName, string? clrAssemblyName)
        {
            return false;
        }
 
        internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, SerializationInfo serInfo)
        {
            return false;
        }
 
        internal virtual void WriteAnyType(XmlWriterDelegator xmlWriter, object value)
        {
            xmlWriter.WriteAnyType(value);
        }
 
        internal virtual void WriteString(XmlWriterDelegator xmlWriter, string value)
        {
            xmlWriter.WriteString(value);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void WriteString(XmlWriterDelegator xmlWriter, string? value, XmlDictionaryString name, XmlDictionaryString? ns)
        {
            if (value == null)
                WriteNull(xmlWriter, typeof(string), true/*isMemberTypeSerializable*/, name, ns);
            else
            {
                xmlWriter.WriteStartElementPrimitive(name, ns);
                xmlWriter.WriteString(value);
                xmlWriter.WriteEndElementPrimitive();
            }
        }
 
        internal virtual void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value)
        {
            xmlWriter.WriteBase64(value);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value, XmlDictionaryString name, XmlDictionaryString ns)
        {
            if (value == null)
                WriteNull(xmlWriter, typeof(byte[]), true/*isMemberTypeSerializable*/, name, ns);
            else
            {
                xmlWriter.WriteStartElementPrimitive(name, ns);
                xmlWriter.WriteBase64(value);
                xmlWriter.WriteEndElementPrimitive();
            }
        }
 
        internal virtual void WriteUri(XmlWriterDelegator xmlWriter, Uri value)
        {
            xmlWriter.WriteUri(value);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void WriteUri(XmlWriterDelegator xmlWriter, Uri value, XmlDictionaryString name, XmlDictionaryString ns)
        {
            if (value == null)
                WriteNull(xmlWriter, typeof(Uri), true/*isMemberTypeSerializable*/, name, ns);
            else
            {
                xmlWriter.WriteStartElementPrimitive(name, ns);
                xmlWriter.WriteUri(value);
                xmlWriter.WriteEndElementPrimitive();
            }
        }
 
        internal virtual void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName value)
        {
            xmlWriter.WriteQName(value);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName? value, XmlDictionaryString name, XmlDictionaryString? ns)
        {
            if (value == null)
                WriteNull(xmlWriter, typeof(XmlQualifiedName), true/*isMemberTypeSerializable*/, name, ns);
            else
            {
                if (ns != null && ns.Value != null && ns.Value.Length > 0)
                    xmlWriter.WriteStartElement(Globals.ElementPrefix, name, ns);
                else
                    xmlWriter.WriteStartElement(name, ns);
                xmlWriter.WriteQName(value);
                xmlWriter.WriteEndElement();
            }
        }
 
        internal void HandleGraphAtTopLevel(XmlWriterDelegator writer, object obj, DataContract contract)
        {
            writer.WriteXmlnsAttribute(Globals.XsiPrefix, DictionaryGlobals.SchemaInstanceNamespace);
            if (contract.IsISerializable)
            {
                writer.WriteXmlnsAttribute(Globals.XsdPrefix, DictionaryGlobals.SchemaNamespace);
            }
 
            OnHandleReference(writer, obj, true /*canContainReferences*/);
        }
 
        internal virtual bool OnHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference)
        {
            if (xmlWriter.depth < depthToCheckCyclicReference)
                return false;
            if (canContainCyclicReference)
            {
                if (_byValObjectsInScope.Contains(obj))
                    throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotSerializeObjectWithCycles, DataContract.GetClrTypeFullName(obj.GetType())));
                _byValObjectsInScope.Push(obj);
            }
            return false;
        }
 
        internal virtual void OnEndHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference)
        {
            if (xmlWriter.depth < depthToCheckCyclicReference)
                return;
            if (canContainCyclicReference)
            {
                _byValObjectsInScope.Pop(obj);
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void WriteNull(XmlWriterDelegator xmlWriter, Type memberType, bool isMemberTypeSerializable)
        {
            CheckIfTypeSerializable(memberType, isMemberTypeSerializable);
            WriteNull(xmlWriter);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void WriteNull(XmlWriterDelegator xmlWriter, Type memberType, bool isMemberTypeSerializable, XmlDictionaryString name, XmlDictionaryString? ns)
        {
            xmlWriter.WriteStartElement(name, ns);
            WriteNull(xmlWriter, memberType, isMemberTypeSerializable);
            xmlWriter.WriteEndElement();
        }
 
        internal void IncrementArrayCount(XmlWriterDelegator xmlWriter, Array array)
        {
            IncrementCollectionCount(xmlWriter, array.GetLength(0));
        }
 
        internal void IncrementCollectionCount(XmlWriterDelegator xmlWriter, ICollection collection)
        {
            IncrementCollectionCount(xmlWriter, collection.Count);
        }
 
        internal void IncrementCollectionCountGeneric<T>(XmlWriterDelegator xmlWriter, ICollection<T> collection)
        {
            IncrementCollectionCount(xmlWriter, collection.Count);
        }
 
        private void IncrementCollectionCount(XmlWriterDelegator xmlWriter, int size)
        {
            IncrementItemCount(size);
            WriteArraySize(xmlWriter, size);
        }
 
        internal virtual void WriteArraySize(XmlWriterDelegator xmlWriter, int size)
        {
        }
 
        internal static bool IsMemberTypeSameAsMemberValue(object obj, Type memberType)
        {
            if (obj == null || memberType == null)
                return false;
 
            return obj.GetType().TypeHandle.Equals(memberType.TypeHandle);
        }
 
        internal static T GetDefaultValue<T>()
        {
            return default(T)!;
        }
 
        internal static T GetNullableValue<T>(Nullable<T> value) where T : struct
        {
            // value.Value will throw if hasValue is false
            return value!.Value;
        }
 
        internal static void ThrowRequiredMemberMustBeEmitted(string memberName, Type type)
        {
            throw new SerializationException(SR.Format(SR.RequiredMemberMustBeEmitted, memberName, type.FullName));
        }
 
        internal static bool GetHasValue<T>(Nullable<T> value) where T : struct
        {
            return value.HasValue;
        }
 
        internal void WriteIXmlSerializable(XmlWriterDelegator xmlWriter, object obj)
        {
            _xmlSerializableWriter ??= new XmlSerializableWriter();
            WriteIXmlSerializable(xmlWriter, obj, _xmlSerializableWriter);
        }
 
        internal static void WriteRootIXmlSerializable(XmlWriterDelegator xmlWriter, object obj)
        {
            WriteIXmlSerializable(xmlWriter, obj, new XmlSerializableWriter());
        }
 
        private static void WriteIXmlSerializable(XmlWriterDelegator xmlWriter, object obj, XmlSerializableWriter xmlSerializableWriter)
        {
            xmlSerializableWriter.BeginWrite(xmlWriter.Writer, obj);
            IXmlSerializable? xmlSerializable = obj as IXmlSerializable;
            if (xmlSerializable != null)
                xmlSerializable.WriteXml(xmlSerializableWriter);
            else
            {
                XmlElement? xmlElement = obj as XmlElement;
                if (xmlElement != null)
                    xmlElement.WriteTo(xmlSerializableWriter);
                else
                {
                    XmlNode[]? xmlNodes = obj as XmlNode[];
                    if (xmlNodes != null)
                        foreach (XmlNode xmlNode in xmlNodes)
                            xmlNode.WriteTo(xmlSerializableWriter);
                    else
                        throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownXmlType, DataContract.GetClrTypeFullName(obj.GetType())));
                }
            }
            xmlSerializableWriter.EndWrite();
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        internal static void GetObjectData(ISerializable obj, SerializationInfo serInfo, StreamingContext context)
        {
#pragma warning disable SYSLIB0050 // ISerializable.GetObjectData is obsolete
            obj.GetObjectData(serInfo, context);
#pragma warning restore SYSLIB0050
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        public void WriteISerializable(XmlWriterDelegator xmlWriter, ISerializable obj)
        {
            Type objType = obj.GetType();
#pragma warning disable SYSLIB0050 // SerializationInfo ctor is obsolete
            var serInfo = new SerializationInfo(objType, XmlObjectSerializer.FormatterConverter /*!UnsafeTypeForwardingEnabled is always false*/);
#pragma warning restore SYSLIB0050
            GetObjectData(obj, serInfo, GetStreamingContext());
 
            // (!UnsafeTypeForwardingEnabled) is always false
            //if (!UnsafeTypeForwardingEnabled && serInfo.AssemblyName == Globals.MscorlibAssemblyName)
            //{
            //    // Throw if a malicious type tries to set its assembly name to "0" to get deserialized in mscorlib
            //    throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ISerializableAssemblyNameSetToZero, DataContract.GetClrTypeFullName(obj.GetType())));
            //}
 
            WriteSerializationInfo(xmlWriter, objType, serInfo);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void WriteSerializationInfo(XmlWriterDelegator xmlWriter, Type objType, SerializationInfo serInfo)
        {
            if (DataContract.GetClrTypeFullName(objType) != serInfo.FullTypeName)
            {
                if (DataContractResolver != null)
                {
                    XmlDictionaryString? typeName, typeNs;
                    if (ResolveType(serInfo.ObjectType, objType, out typeName, out typeNs))
                    {
                        xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, typeName, typeNs);
                    }
                }
                else
                {
                    string typeName, typeNs;
                    DataContract.GetDefaultXmlName(serInfo.FullTypeName, out typeName, out typeNs);
                    xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(typeName), DataContract.GetClrTypeString(typeNs));
                }
            }
 
            WriteClrTypeInfo(xmlWriter, objType, serInfo);
            IncrementItemCount(serInfo.MemberCount);
            foreach (SerializationEntry serEntry in serInfo)
            {
                XmlDictionaryString name = DataContract.GetClrTypeString(DataContract.EncodeLocalName(serEntry.Name));
                xmlWriter.WriteStartElement(name, DictionaryGlobals.EmptyString);
                object? obj = serEntry.Value;
                if (obj == null)
                {
                    WriteNull(xmlWriter);
                }
                else
                {
                    InternalSerializeReference(xmlWriter, obj, false /*isDeclaredType*/, false /*writeXsiType*/, -1, Globals.TypeOfObject.TypeHandle);
                }
 
                xmlWriter.WriteEndElement();
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        protected virtual void WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle)
        {
            dataContract.WriteXmlValue(xmlWriter, obj, this);
        }
 
        protected virtual void WriteNull(XmlWriterDelegator xmlWriter)
        {
            XmlObjectSerializer.WriteNull(xmlWriter);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteResolvedTypeInfo(XmlWriterDelegator writer, Type objectType, Type declaredType)
        {
            XmlDictionaryString? typeName, typeNamespace;
            if (ResolveType(objectType, declaredType, out typeName, out typeNamespace))
            {
                WriteTypeInfo(writer, typeName, typeNamespace);
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private bool ResolveType(Type objectType, Type declaredType, [NotNullWhen(true)] out XmlDictionaryString? typeName, [NotNullWhen(true)] out XmlDictionaryString? typeNamespace)
        {
            Debug.Assert(DataContractResolver != null);
 
            if (!DataContractResolver.TryResolveType(objectType, declaredType, KnownTypeResolver, out typeName, out typeNamespace))
            {
                throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedFalse, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)));
            }
            if (typeName == null)
            {
                if (typeNamespace == null)
                {
                    return false;
                }
                else
                {
                    throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedNull, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)));
                }
            }
            if (typeNamespace == null)
            {
                throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedNull, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)));
            }
            return true;
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        protected virtual bool WriteTypeInfo(XmlWriterDelegator writer, DataContract contract, DataContract declaredContract)
        {
            if (!XmlObjectSerializer.IsContractDeclared(contract, declaredContract))
            {
                if (DataContractResolver == null)
                {
                    WriteTypeInfo(writer, contract.Name, contract.Namespace);
                    return true;
                }
                else
                {
                    WriteResolvedTypeInfo(writer, contract.OriginalUnderlyingType, declaredContract.OriginalUnderlyingType);
                    return false;
                }
            }
            return false;
        }
 
        protected virtual void WriteTypeInfo(XmlWriterDelegator writer, string dataContractName, string? dataContractNamespace)
        {
            writer.WriteAttributeQualifiedName(Globals.XsiPrefix, DictionaryGlobals.XsiTypeLocalName, DictionaryGlobals.SchemaInstanceNamespace, dataContractName, dataContractNamespace);
        }
 
        protected virtual void WriteTypeInfo(XmlWriterDelegator writer, XmlDictionaryString dataContractName, XmlDictionaryString dataContractNamespace)
        {
            writer.WriteAttributeQualifiedName(Globals.XsiPrefix, DictionaryGlobals.XsiTypeLocalName, DictionaryGlobals.SchemaInstanceNamespace, dataContractName, dataContractNamespace);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        public void WriteExtensionData(XmlWriterDelegator xmlWriter, ExtensionDataObject? extensionData, int memberIndex)
        {
            if (IgnoreExtensionDataObject || extensionData == null)
                return;
 
            IList<ExtensionDataMember>? members = extensionData.Members;
            if (members != null)
            {
                for (int i = 0; i < members.Count; i++)
                {
                    ExtensionDataMember member = members[i];
                    if (member.MemberIndex == memberIndex)
                    {
                        WriteExtensionDataMember(xmlWriter, member);
                    }
                }
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteExtensionDataMember(XmlWriterDelegator xmlWriter, ExtensionDataMember member)
        {
            xmlWriter.WriteStartElement(member.Name, member.Namespace);
            IDataNode? dataNode = member.Value;
            WriteExtensionDataValue(xmlWriter, dataNode);
            xmlWriter.WriteEndElement();
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal virtual void WriteExtensionDataTypeInfo(XmlWriterDelegator xmlWriter, IDataNode dataNode)
        {
            if (dataNode.DataContractName != null)
                WriteTypeInfo(xmlWriter, dataNode.DataContractName, dataNode.DataContractNamespace);
 
            WriteClrTypeInfo(xmlWriter, dataNode.DataType, dataNode.ClrTypeName, dataNode.ClrAssemblyName);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal void WriteExtensionDataValue(XmlWriterDelegator xmlWriter, IDataNode? dataNode)
        {
            IncrementItemCount(1);
            if (dataNode == null)
            {
                WriteNull(xmlWriter);
                return;
            }
 
            if (dataNode.PreservesReferences
                && OnHandleReference(xmlWriter, dataNode.Value ?? dataNode, canContainCyclicReference: true))
                return;
 
            Type dataType = dataNode.DataType;
            if (dataType == Globals.TypeOfClassDataNode)
                WriteExtensionClassData(xmlWriter, (ClassDataNode)dataNode);
            else if (dataType == Globals.TypeOfCollectionDataNode)
                WriteExtensionCollectionData(xmlWriter, (CollectionDataNode)dataNode);
            else if (dataType == Globals.TypeOfXmlDataNode)
                WriteExtensionXmlData(xmlWriter, (XmlDataNode)dataNode);
            else if (dataType == Globals.TypeOfISerializableDataNode)
                WriteExtensionISerializableData(xmlWriter, (ISerializableDataNode)dataNode);
            else
            {
                WriteExtensionDataTypeInfo(xmlWriter, dataNode);
 
                if (dataType == Globals.TypeOfObject)
                {
                    // NOTE: serialize value in DataNode<object> since it may contain non-primitive
                    // deserialized object (ex. empty class)
                    object? o = dataNode.Value;
                    if (o != null)
                        InternalSerialize(xmlWriter, o, false /*isDeclaredType*/, false /*writeXsiType*/, -1, o.GetType().TypeHandle);
                }
                else
                    xmlWriter.WriteExtensionData(dataNode);
            }
            if (dataNode.PreservesReferences)
                OnEndHandleReference(xmlWriter, (dataNode.Value ?? dataNode), true  /*canContainCyclicReference*/);
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        internal bool TryWriteDeserializedExtensionData(XmlWriterDelegator xmlWriter, IDataNode dataNode)
        {
            object? o = dataNode.Value;
            if (o == null)
                return false;
 
            Type declaredType = (dataNode.DataContractName == null) ? o.GetType() : Globals.TypeOfObject;
            InternalSerialize(xmlWriter, o, false /*isDeclaredType*/, false /*writeXsiType*/, -1, declaredType.TypeHandle);
            return true;
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteExtensionClassData(XmlWriterDelegator xmlWriter, ClassDataNode dataNode)
        {
            if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode))
            {
                WriteExtensionDataTypeInfo(xmlWriter, dataNode);
 
                IList<ExtensionDataMember>? members = dataNode.Members;
                if (members != null)
                {
                    for (int i = 0; i < members.Count; i++)
                    {
                        WriteExtensionDataMember(xmlWriter, members[i]);
                    }
                }
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteExtensionCollectionData(XmlWriterDelegator xmlWriter, CollectionDataNode dataNode)
        {
            if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode))
            {
                WriteExtensionDataTypeInfo(xmlWriter, dataNode);
 
                WriteArraySize(xmlWriter, dataNode.Size);
 
                IList<IDataNode?>? items = dataNode.Items;
                if (items != null)
                {
                    for (int i = 0; i < items.Count; i++)
                    {
                        xmlWriter.WriteStartElement(dataNode.ItemName!, dataNode.ItemNamespace);
                        WriteExtensionDataValue(xmlWriter, items[i]);
                        xmlWriter.WriteEndElement();
                    }
                }
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteExtensionISerializableData(XmlWriterDelegator xmlWriter, ISerializableDataNode dataNode)
        {
            if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode))
            {
                WriteExtensionDataTypeInfo(xmlWriter, dataNode);
 
                if (dataNode.FactoryTypeName != null)
                    xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, dataNode.FactoryTypeName, dataNode.FactoryTypeNamespace);
 
                IList<ISerializableDataMember>? members = dataNode.Members;
                if (members != null)
                {
                    for (int i = 0; i < members.Count; i++)
                    {
                        ISerializableDataMember member = members[i];
                        xmlWriter.WriteStartElement(member.Name, string.Empty);
                        WriteExtensionDataValue(xmlWriter, member.Value);
                        xmlWriter.WriteEndElement();
                    }
                }
            }
        }
 
        [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
        [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
        private void WriteExtensionXmlData(XmlWriterDelegator xmlWriter, XmlDataNode dataNode)
        {
            if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode))
            {
                IList<XmlAttribute>? xmlAttributes = dataNode.XmlAttributes;
                if (xmlAttributes != null)
                {
                    foreach (XmlAttribute attribute in xmlAttributes)
                        attribute.WriteTo(xmlWriter.Writer);
                }
                WriteExtensionDataTypeInfo(xmlWriter, dataNode);
 
                IList<XmlNode>? xmlChildNodes = dataNode.XmlChildNodes;
                if (xmlChildNodes != null)
                {
                    foreach (XmlNode node in xmlChildNodes)
                        node.WriteTo(xmlWriter.Writer);
                }
            }
        }
    }
}