/// <summary> /// Check to see if the object has been serialized before. If it has, then make sure /// that the reference information for it is added. /// </summary> /// <remarks>This routine has the overloaded</remarks> /// <param name="_object">The object that's being serialized</param> /// <param name="_elementForObject"> /// The element that the object is being serialized to /// </param> /// <returns>TRUE if the object is a duplicate, FALSE if it is a "new" object</returns> private bool HandleDuplicateReferences(object _object, XmlElement _elementForObject) { var oType = _object.GetType(); if (oType.IsPrimitive) { return(false); } if (oType == TYPEOF_STRING && !m_context.DuplicateStringsCanBeReferredTo) { return(false); } if (oType.IsEnum) { return(false); } if (m_references.TryGetValue(_object, out var refElem)) // The object was serialized already { if (ReferenceEquals(_elementForObject, refElem)) // If this IS the referenced element, then skip it { return(false); } var refId = XmlExtensions.GetAttributeValue(refElem, m_context.ReferenceIdAttributeName); if (refId == null) // The object that was serialized doesn't have its RefID set yet { refId = m_refId.ToString(); XmlExtensions.AddAttribute(refElem, m_context.ReferenceIdAttributeName, refId); m_refId++; } // Add the "ReferTo" attribute to the xml XmlExtensions.AddAttribute(_elementForObject, m_context.ReferToAttributeName, refId); // Remove a "Type" attribute (if it exists) because this becomes redundant with // the presence of RefTo XmlExtensions.RemoveAttribute(_elementForObject, m_context.TypeAttributeName); return(true); } m_references.Add(_object, _elementForObject); return(false); }
/// <summary> /// This "different" serializer handles Properties, not Fields, and conforms to the /// conventions found in Microsoft's Entity Framework /// </summary> /// <param name="_object"></param> /// <param name="_useType"></param> /// <param name="_elementForObject"></param> private void SerializeUsingEntitySemantics(object _object, Type _useType, XmlElement _elementForObject) { XmlExtensions.AddAttribute(_elementForObject, m_context.UseEntitySemanticsAttributeName, "1"); // Gets (cached) type data pertinent to serializing an Entity var typeData = CEntityTypeData.GetTypeData(_useType); // First serialize all the "single" properties- No collections for (var i = 0; i < typeData.NonCollectionProperties.Length; i++) { var prop = typeData.NonCollectionProperties[i]; var val = prop.GetValue(_object); FrameworkSerialize(prop.Name, val, _elementForObject, prop.PropertyType); } // Now serialize all the collections which are presumed to be the "Many" in a // Many-To-One relationship. The exact Type of the collection in this object is // irrelevant because the collection should merely implement ICollection for the // deserialization, and the deserialization target class should determine the exact // collection Type, or if its an Interface the PreferredCollectionType on the // AUseEntitySemantics attribute will dictate what to create. for (var i = 0; i < typeData.CollectionProperties.Length; i++) { var col = typeData.CollectionProperties[i]; var collectionElement = XmlExtensions.AddElement(_elementForObject, col.Name); Type elementType = null; // set if the PropertyType is a generic collection if (col.PropertyType.IsGenericType) { elementType = col.PropertyType.GetGenericArguments()[0]; } foreach (var item in col.GetValue(_object) as System.Collections.IEnumerable) { FrameworkSerialize(m_context.ArrayElementName, item, collectionElement, elementType); } } }
/// <summary> /// Create an XmlElement for an object. Do not populate the new element. /// </summary> /// <remarks> /// FieldRenamers are NOT called at this level- the caller of this method needs to /// handle all field renaming /// </remarks> /// <param name="_elementName"> /// The name that should be assigned to the newly created element /// </param> /// <param name="_expectedType"> /// The expected type of the object. Used to decide whether or not to add explicit Type /// data /// </param> /// <param name="_object">The object that is being serialized</param> /// <param name="_parentNode">The XML node that the new node will be a child of</param> /// <returns>An XmlElement with some basic attributes for an object</returns> private XmlElement CreateElementForValue(string _elementName, object _object, XmlNode _parentNode, Type _expectedType) { var fixedElementName = FixMemberName(_elementName); var elem = XmlExtensions.CreateElement(_parentNode, fixedElementName); if (_object == null) { XmlExtensions.AddAttribute(elem, m_context.NullAttributeName, m_context.NullAttributeValue); } else { var oType = _object.GetType(); oType = CEntityTypeData.StripProxyType(oType); if (_expectedType != oType) // There must be a Type attribute added { XmlExtensions.AddAttribute(elem, m_context.TypeAttributeName, oType.AssemblyQualifiedName); } } return(elem); }
/// <summary> /// Use this method when an Array field needs to be added to the XML serialization /// </summary> /// <remarks> /// For element types that are primitives and strings, build a comma-separated list of /// values that should end up taking less space. For all other element types, create /// child-elements for each array element. /// </remarks> /// <param name="_array">The array to add to the XML Element</param> /// <param name="_elementToAddTo">The XML Element that is to contain the array</param> private void AddArrayToXml(Array _array, XmlElement _elementToAddTo) { if (_array.Rank != 1) { AddMultiDimensionalArray(_array, _elementToAddTo); return; } var arrayType = _array.GetType(); var elementType = arrayType.GetElementType(); var count = _array.Length; var lowerBound = _array.GetLowerBound(0); var upperBound = _array.GetUpperBound(0); XmlExtensions.AddAttribute(_elementToAddTo, m_context.ArrayAttributeName, count); if (lowerBound != 0) { XmlExtensions.AddAttribute(_elementToAddTo, m_context.ArrayLowerBoundAttribute, lowerBound); } if (elementType.IsPrimitive && !m_context.AllArraysHaveExplicitElements) { // Helper doesn't care what the element type is, so we screen it first by making // sure its a primitive. _elementToAddTo.InnerText = Lib.ConvertArrayToString(_array); } else if (elementType == TYPEOF_STRING && !m_context.AllArraysHaveExplicitElements) { // Strings could theoretically be treated with the same helper used above IF // they never contained commas. var str = ConvertStringArrayToCommaList(_array); _elementToAddTo.InnerText = str; } else { var skipped = false; var elementName = GetNameForCollectionElement(); for (var i = lowerBound; i <= upperBound; i++) { var arrayElementValue = _array.GetValue(i); if (arrayElementValue == null && m_context.RemoveNullValuesFromXml) { skipped = true; } else { var elem = FrameworkSerialize(elementName, arrayElementValue, _elementToAddTo, elementType); if (m_context.ArrayElementsIncludeIndicies || skipped) { XmlExtensions.AddAttribute(elem, m_context.ArrayIndexAttributeName, i); } skipped = false; } } } }