File: System\Runtime\Serialization\ExtensionDataObject.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.Generic;
using System.Globalization;
using System.Xml;
 
namespace System.Runtime.Serialization
{
    public sealed class ExtensionDataObject
    {
        private IList<ExtensionDataMember>? _members;
 
        internal ExtensionDataObject()
        {
        }
 
        internal IList<ExtensionDataMember>? Members
        {
            get { return _members; }
            set { _members = value; }
        }
    }
 
    internal sealed class ExtensionDataMember
    {
        private IDataNode? _value;
        private int _memberIndex;
 
        public ExtensionDataMember(string name, string ns)
        {
            Name = name;
            Namespace = ns;
        }
 
        public string Name { get; }
 
        public string Namespace { get; }
 
        public IDataNode? Value
        {
            get { return _value; }
            set { _value = value; }
        }
 
        public int MemberIndex
        {
            get { return _memberIndex; }
            set { _memberIndex = value; }
        }
    }
 
    internal interface IDataNode
    {
        Type DataType { get; }
        object? Value { get; set; }  // boxes for primitives
        string? DataContractName { get; set; }
        string? DataContractNamespace { get; set; }
        string? ClrTypeName { get; set; }
        string? ClrAssemblyName { get; set; }
        string Id { get; set; }
        bool PreservesReferences { get; }
 
        // NOTE: consider moving below APIs to DataNode<T> if IDataNode API is made public
        void GetData(ElementData element);
        bool IsFinalValue { get; set; }
        void Clear();
    }
 
    internal class DataNode<T> : IDataNode
    {
        protected Type dataType;
        private T _value = default!;
        private string? _dataContractName;
        private string? _dataContractNamespace;
        private string? _clrTypeName;
        private string? _clrAssemblyName;
        private string _id = Globals.NewObjectId;
        private bool _isFinalValue;
 
        internal DataNode()
        {
            this.dataType = typeof(T);
            _isFinalValue = true;
        }
 
        internal DataNode(T value)
            : this()
        {
            _value = value;
        }
 
        public Type DataType
        {
            get { return dataType; }
        }
 
        public object? Value
        {
            get { return _value; }
            set { _value = (T)value!; }
        }
 
        bool IDataNode.IsFinalValue
        {
            get { return _isFinalValue; }
            set { _isFinalValue = value; }
        }
 
        public T GetValue()
        {
            return _value;
        }
 
        public string? DataContractName
        {
            get { return _dataContractName; }
            set { _dataContractName = value; }
        }
 
        public string? DataContractNamespace
        {
            get { return _dataContractNamespace; }
            set { _dataContractNamespace = value; }
        }
 
        public string? ClrTypeName
        {
            get { return _clrTypeName; }
            set { _clrTypeName = value; }
        }
 
        public string? ClrAssemblyName
        {
            get { return _clrAssemblyName; }
            set { _clrAssemblyName = value; }
        }
 
        public bool PreservesReferences
        {
            get { return (Id != Globals.NewObjectId); }
        }
 
        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }
 
        public virtual void GetData(ElementData element)
        {
            element.dataNode = this;
            element.attributeCount = 0;
            element.childElementIndex = 0;
 
            if (DataContractName != null)
                AddQualifiedNameAttribute(element, Globals.XsiPrefix, Globals.XsiTypeLocalName, Globals.SchemaInstanceNamespace, DataContractName, DataContractNamespace);
            if (ClrTypeName != null)
                element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrTypeLocalName, ClrTypeName);
            if (ClrAssemblyName != null)
                element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, ClrAssemblyName);
        }
 
        public virtual void Clear()
        {
            // dataContractName not cleared because it is used when re-serializing from unknown data
            _clrTypeName = _clrAssemblyName = null;
        }
 
        internal static void AddQualifiedNameAttribute(ElementData element, string elementPrefix, string elementName, string elementNs, string valueName, string? valueNs)
        {
            string prefix = ExtensionDataReader.GetPrefix(valueNs);
            element.AddAttribute(elementPrefix, elementNs, elementName, prefix + ":" + valueName);
 
            bool prefixDeclaredOnElement = false;
            if (element.attributes != null)
            {
                for (int i = 0; i < element.attributes.Length; i++)
                {
                    AttributeData attribute = element.attributes[i];
                    if (attribute != null && attribute.prefix == Globals.XmlnsPrefix && attribute.localName == prefix)
                    {
                        prefixDeclaredOnElement = true;
                        break;
                    }
                }
            }
            if (!prefixDeclaredOnElement)
                element.AddAttribute(Globals.XmlnsPrefix, Globals.XmlnsNamespace, prefix, valueNs);
        }
    }
 
    internal sealed class ClassDataNode : DataNode<object>
    {
        private IList<ExtensionDataMember>? _members;
 
        internal ClassDataNode()
        {
            dataType = Globals.TypeOfClassDataNode;
        }
 
        internal IList<ExtensionDataMember>? Members
        {
            get { return _members; }
            set { _members = value; }
        }
 
        public override void Clear()
        {
            base.Clear();
            _members = null;
        }
    }
 
    internal sealed class XmlDataNode : DataNode<object>
    {
        private IList<XmlAttribute>? _xmlAttributes;
        private IList<XmlNode>? _xmlChildNodes;
        private XmlDocument? _ownerDocument;
 
        internal XmlDataNode()
        {
            dataType = Globals.TypeOfXmlDataNode;
        }
 
        internal IList<XmlAttribute>? XmlAttributes
        {
            get { return _xmlAttributes; }
            set { _xmlAttributes = value; }
        }
 
        internal IList<XmlNode>? XmlChildNodes
        {
            get { return _xmlChildNodes; }
            set { _xmlChildNodes = value; }
        }
 
        internal XmlDocument? OwnerDocument
        {
            get { return _ownerDocument; }
            set { _ownerDocument = value; }
        }
 
        public override void Clear()
        {
            base.Clear();
            _xmlAttributes = null;
            _xmlChildNodes = null;
            _ownerDocument = null;
        }
    }
 
    internal sealed class CollectionDataNode : DataNode<Array>
    {
        private IList<IDataNode?>? _items;
        private string? _itemName;
        private string? _itemNamespace;
        private int _size = -1;
 
        internal CollectionDataNode()
        {
            dataType = Globals.TypeOfCollectionDataNode;
        }
 
        internal IList<IDataNode?>? Items
        {
            get { return _items; }
            set { _items = value; }
        }
 
        internal string? ItemName
        {
            get { return _itemName; }
            set { _itemName = value; }
        }
 
        internal string? ItemNamespace
        {
            get { return _itemNamespace; }
            set { _itemNamespace = value; }
        }
 
        internal int Size
        {
            get { return _size; }
            set { _size = value; }
        }
 
        public override void GetData(ElementData element)
        {
            base.GetData(element);
 
            element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ArraySizeLocalName, Size.ToString(NumberFormatInfo.InvariantInfo));
        }
 
        public override void Clear()
        {
            base.Clear();
            _items = null;
            _size = -1;
        }
    }
 
    internal sealed class ISerializableDataNode : DataNode<object>
    {
        private string? _factoryTypeName;
        private string? _factoryTypeNamespace;
        private IList<ISerializableDataMember>? _members;
 
        internal ISerializableDataNode()
        {
            dataType = Globals.TypeOfISerializableDataNode;
        }
 
        internal string? FactoryTypeName
        {
            get { return _factoryTypeName; }
            set { _factoryTypeName = value; }
        }
 
        internal string? FactoryTypeNamespace
        {
            get { return _factoryTypeNamespace; }
            set { _factoryTypeNamespace = value; }
        }
 
        internal IList<ISerializableDataMember>? Members
        {
            get { return _members; }
            set { _members = value; }
        }
 
        public override void GetData(ElementData element)
        {
            base.GetData(element);
 
            if (FactoryTypeName != null)
                AddQualifiedNameAttribute(element, Globals.SerPrefix, Globals.ISerializableFactoryTypeLocalName, Globals.SerializationNamespace, FactoryTypeName, FactoryTypeNamespace);
        }
 
        public override void Clear()
        {
            base.Clear();
            _members = null;
            _factoryTypeName = _factoryTypeNamespace = null;
        }
    }
 
    internal sealed class ISerializableDataMember
    {
        private IDataNode? _value;
 
        public ISerializableDataMember(string name)
        {
            Name = name;
        }
 
        internal string Name { get; }
 
        internal IDataNode? Value
        {
            get { return _value; }
            set { _value = value; }
        }
    }
}