private Type GetReadTargetType(BXmlPropertyAttribute propertyAttribute, PropertyInfo property)
        {
            Type targetType = null;

            if (propertyAttribute.Collection)
            {
                foreach (Type iface in property.PropertyType.GetInterfaces())
                {
                    if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                    {
                        targetType = iface.GetGenericArguments()[0];
                        break;
                    }
                }
                if (targetType == null)
                {
                    throw new InvalidOperationException($"The type of the value {property.DeclaringType.FullName}.{property.Name} must implement IEnumerable interface");
                }
            }
            else
            {
                targetType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
            }
            return(targetType);
        }
Example #2
0
        private void SerializeProperty_Collection(XmlElement element, BXmlPropertyAttribute propertyAttribute, object propertyValue)
        {
            var collectionElement = Document.CreateElement(propertyAttribute.Name);

            foreach (object o in (propertyValue as IEnumerable))
            {
                collectionElement.AppendChild(Serialize(o));
            }

            element.AppendChild(collectionElement);
        }
        private bool ReadAttributeProperty(XmlElement element, Type type, BXmlPropertyAttribute propertyAttribute, string attributePrefix, PropertyInfo property, IReader reader)
        {
            object propertyValue = ReadAttribute(type, element, property.Name, property.PropertyType, propertyAttribute, attributePrefix);

            if (propertyValue != null)
            {
                reader.Set(property, propertyValue);
                return(true);
            }
            return(false);
        }
        private bool ReadCollectionProperty(XmlElement element, BXmlPropertyAttribute propertyAttribute, PropertyInfo property, IReader reader, Type targetType, BXmlElementAttribute elementAttribute1, BXmlSelectAttribute selectAttribute)
        {
            object collection = ReadCollectionProperty_InitializeCollection(property, targetType, reader);

            MethodInfo method = collection.GetType().GetMethod("Add", new Type[] { targetType });

            if (method == null)
            {
                throw new InvalidOperationException($"The type of the property {property.DeclaringType.FullName}.{property.Name} has no Add({targetType.FullName}) method");
            }

            var collectionElement = FindChildElement(element, propertyAttribute.Name);

            if (collectionElement == null)
            {
                return(false);
            }

            object[] parameters = new object[] { null };

            Func <XmlElement, object> deserializer;

            if (elementAttribute1 != null)
            {
                deserializer = e => Deserialize(e, targetType);
            }
            else
            {
                deserializer = e => Deserialize(e, selectAttribute.Options);
            }

            foreach (XmlNode node in collectionElement.ChildNodes)
            {
                if (node is not XmlElement childElement)
                {
                    continue;
                }

                parameters[0] = deserializer(childElement);
                method.Invoke(collection, parameters);
            }

            if (reader.CanSet(property))
            {
                if (property.PropertyType.IsArray)
                {
                    collection = collection.GetType().GetMethod("ToArray", new Type[] { }).Invoke(collection, Array.Empty <object>());
                }
                reader.Set(property, collection);
            }

            return(true);
        }
Example #5
0
        private void SerializeProperty_Child(XmlElement element, BXmlPropertyAttribute propertyAttribute, object propertyValue)
        {
            string forceName1 = null;

            if (!string.IsNullOrEmpty(propertyAttribute.Name))
            {
                forceName1 = propertyAttribute.Name;
            }

            if (propertyAttribute.FlattenChild)
            {
                SerializeTo(propertyValue, element, propertyAttribute.Name);
            }
            else
            {
                element.AppendChild(Serialize(propertyValue, forceName1));
            }
        }
        private bool ReadChildElementProperty(XmlElement element, BXmlPropertyAttribute propertyAttribute, PropertyInfo property, IReader reader, Type targetType, BXmlElementAttribute elementAttribute1, BXmlSelectAttribute selectAttribute)
        {
            string elementToSearch = null;

            if (elementAttribute1 == null && string.IsNullOrEmpty(propertyAttribute.Name))
            {
                throw new InvalidOperationException($"The value of the property {property.DeclaringType.FullName}.{property.Name} must have the name specified in the {nameof(BXmlPropertyAttribute)}");
            }

            elementToSearch = propertyAttribute.Name ?? elementAttribute1?.Name;

            if (!propertyAttribute.FlattenChild)
            {
                return(ReadChildElementProperty_NotFlatten(element, property, reader, targetType, elementAttribute1, selectAttribute, elementToSearch));
            }
            else
            {
                return(ReadChildElementProperty_Flatten(element, property, reader, targetType, elementToSearch));
            }
        }
        private void ReadProperty(XmlElement element, Type type, BXmlPropertyAttribute propertyAttribute, string attributePrefix, PropertyInfo property, IReader reader)
        {
            bool found      = false;
            Type targetType = GetReadTargetType(propertyAttribute, property);

            BXmlElementAttribute elementAttribute1 = targetType.GetCustomAttribute <BXmlElementAttribute>();
            BXmlSelectAttribute  selectAttribute   = targetType.GetCustomAttribute <BXmlSelectAttribute>();

            if ((!propertyAttribute.ChildElement || elementAttribute1 == null) && string.IsNullOrEmpty(propertyAttribute.Name))
            {
                throw new InvalidOperationException($"The value of the property {type.FullName}.{property.Name} must have the name specified in the {nameof(BXmlPropertyAttribute)}");
            }

            if ((propertyAttribute.ChildElement || propertyAttribute.Collection) &&
                (elementAttribute1 == null && selectAttribute == null))
            {
                throw new InvalidOperationException($"The type of the property {type.FullName}.{property.Name} must have either {nameof(BXmlElementAttribute)} or {nameof(BXmlSelectAttribute)}");
            }

            if (propertyAttribute.ChildElement)
            {
                found = ReadChildElementProperty(element, propertyAttribute, property, reader, targetType, elementAttribute1, selectAttribute);
            }
            else if (propertyAttribute.Collection)
            {
                found = ReadCollectionProperty(element, propertyAttribute, property, reader, targetType, elementAttribute1, selectAttribute);
            }
            else
            {
                found = ReadAttributeProperty(element, type, propertyAttribute, attributePrefix, property, reader);
            }

            if (!found && !propertyAttribute.Optional)
            {
                throw new InvalidOperationException($"The value of the property {type.FullName}.{property.Name} is not found but the property is not optional");
            }
        }
Example #8
0
        /// <summary>
        /// Serializes a primitive value and adds it as an attribute
        /// </summary>
        /// <param name="element"></param>
        /// <param name="targetObject"></param>
        /// <param name="value"></param>
        /// <param name="property"></param>
        /// <param name="propertyAttribute"></param>
        /// <param name="attributePrefix"></param>
        private void AddAttribute(XmlElement element, object targetObject, object value, PropertyInfo property, BXmlPropertyAttribute propertyAttribute, string attributePrefix)
        {
            var type = SerializerTools.RemoveNullabilityFromType(property.PropertyType);

            for (int i = 0; i < gAddAttributeActions.Length; i++)
            {
                if (gAddAttributeActions[i].Probe(type))
                {
                    AddAttribute(element, propertyAttribute.Name,
                                 gAddAttributeActions[i].Value(type, value),
                                 attributePrefix);
                    return;
                }
            }

            throw new InvalidOperationException($"The type {type.FullName} of the property {targetObject.GetType().FullName}.{property.Name} is not supported to save as an attribute value");
        }
Example #9
0
        private void SerializeProperty(object value, XmlElement element, string attributePrefix, PropertyInfo property, BXmlPropertyAttribute propertyAttribute, object propertyValue)
        {
            if ((!propertyAttribute.ChildElement || propertyAttribute.FlattenChild) && string.IsNullOrEmpty(propertyAttribute.Name))
            {
                throw new InvalidOperationException($"The property {value.GetType().FullName}.{property.Name} must have the Name property specified in {nameof(BXmlPropertyAttribute)} in order to save flatten children, collections or attributes");
            }

            if ((propertyAttribute.ChildElement || propertyAttribute.Collection) && !string.IsNullOrEmpty(attributePrefix))
            {
                throw new InvalidOperationException($"The type {value.GetType().FullName}.{property.Name} is saved as a flatten value but contains child elements and/or collections");
            }

            if (propertyAttribute.ChildElement)
            {
                SerializeProperty_Child(element, propertyAttribute, propertyValue);
            }
            else if (propertyAttribute.Collection)
            {
                SerializeProperty_Collection(element, propertyAttribute, propertyValue);
            }
            else
            {
                AddAttribute(element, value, propertyValue, property, propertyAttribute, attributePrefix);
            }
        }
Example #10
0
        /// <summary>
        /// Serializes a primitive value and adds it as an attribute
        /// </summary>
        /// <param name="element"></param>
        /// <param name="targetObject"></param>
        /// <param name="propertyValue"></param>
        /// <param name="property"></param>
        /// <param name="propertyAttribute"></param>
        /// <param name="attributePrefix"></param>
        private void AddAttribute(XmlElement element, object targetObject, object propertyValue, PropertyInfo property, BXmlPropertyAttribute propertyAttribute, string attributePrefix)
        {
            var propertyType  = property.PropertyType;
            var propertyType1 = Nullable.GetUnderlyingType(propertyType);

            if (propertyType1 != null && propertyType1 != propertyType)
            {
                propertyType = propertyType1;
            }

            if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Measurement <>))
            {
                var textProperty = propertyType.GetProperty("Text");
                AddAttribute(element, propertyAttribute.Name, (string)textProperty.GetValue(propertyValue), attributePrefix);
            }
            else if (propertyType.IsEnum)
            {
                var textValue = propertyValue.ToString();
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(double))
            {
                var textValue = ((double)propertyValue).ToString(CultureInfo.InvariantCulture);
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(float))
            {
                var textValue = ((float)propertyValue).ToString(CultureInfo.InvariantCulture);
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(int))
            {
                var textValue = ((int)propertyValue).ToString(CultureInfo.InvariantCulture);
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(bool))
            {
                var textValue = (bool)propertyValue ? "true" : "false";
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(DateTime))
            {
                var textValue = ((DateTime)propertyValue).ToString("yyyy-MM-dd HH:mm:ss");
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(TimeSpan))
            {
                var textValue = ((TimeSpan)propertyValue).TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else if (propertyType == typeof(string))
            {
                AddAttribute(element, propertyAttribute.Name, (string)propertyValue, attributePrefix);
            }
            else if (propertyType == typeof(BallisticCoefficient))
            {
                var textValue = ((BallisticCoefficient)propertyValue).ToString(CultureInfo.InvariantCulture);
                AddAttribute(element, propertyAttribute.Name, textValue, attributePrefix);
            }
            else
            {
                throw new InvalidOperationException($"The type {propertyType.FullName} of the property {targetObject.GetType().FullName}.{property.Name} is not supported to save as an attribute value");
            }
        }
Example #11
0
        /// <summary>
        /// Reads a simple value from the attribute
        /// </summary>
        /// <param name="type">The type being read</param>
        /// <param name="element"></param>
        /// <param name="propertyName"></param>
        /// <param name="propertyType"></param>
        /// <param name="propertyAttribute"></param>
        /// <param name="attributePrefix"></param>
        /// <returns></returns>
        private object ReadAttribute(Type type, XmlElement element, string propertyName, Type propertyType, BXmlPropertyAttribute propertyAttribute, string attributePrefix)
        {
            object propertyValue = null;

            string name;

            if (string.IsNullOrEmpty(attributePrefix))
            {
                name = propertyAttribute.Name;
            }
            else
            {
                name = $"{attributePrefix}-{propertyAttribute.Name}";
            }

            string propertyText = element.Attributes[name]?.Value;

            if (propertyText != null)
            {
                var propertyType1 = Nullable.GetUnderlyingType(propertyType);
                if (propertyType1 != null && propertyType1 != propertyType)
                {
                    propertyType = propertyType1;
                }
                if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Measurement <>))
                {
                    var ci = propertyType.GetConstructor(new Type[] { typeof(string) });
                    if (ci != null)
                    {
                        try
                        {
                            propertyValue = ci.Invoke(new object[] { propertyText });
                        }
                        catch (Exception)
                        {
                            propertyValue = null;
                        }
                    }
                }
                else if (propertyType.IsEnum)
                {
                    propertyValue = Enum.Parse(propertyType, propertyText);
                }
                else if (propertyType == typeof(double))
                {
                    if (double.TryParse(propertyText, NumberStyles.Float, CultureInfo.InvariantCulture, out double x))
                    {
                        propertyValue = x;
                    }
                }
                else if (propertyType == typeof(float))
                {
                    if (float.TryParse(propertyText, NumberStyles.Float, CultureInfo.InvariantCulture, out float x))
                    {
                        propertyValue = x;
                    }
                }
                else if (propertyType == typeof(int))
                {
                    if (int.TryParse(propertyText, NumberStyles.Any, CultureInfo.InvariantCulture, out int x))
                    {
                        propertyValue = x;
                    }
                }
                else if (propertyType == typeof(bool))
                {
                    propertyValue = propertyText == "true";
                }
                else if (propertyType == typeof(DateTime))
                {
                    if (DateTime.TryParseExact(propertyText, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AllowWhiteSpaces, out DateTime d))
                    {
                        propertyValue = d;
                    }
                    else if (DateTime.TryParseExact(propertyText, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AllowWhiteSpaces, out d))
                    {
                        propertyValue = d;
                    }
                    else if (DateTime.TryParseExact(propertyText, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AllowWhiteSpaces, out d))
                    {
                        propertyValue = d;
                    }
                }
                else if (propertyType == typeof(TimeSpan))
                {
                    if (double.TryParse(propertyText, NumberStyles.Float, CultureInfo.InvariantCulture, out double x))
                    {
                        propertyValue = TimeSpan.FromMilliseconds(x);
                    }
                    else if (TimeSpan.TryParse(propertyText, out TimeSpan ts))
                    {
                        propertyValue = ts;
                    }
                }
                else if (propertyType == typeof(string))
                {
                    propertyValue = propertyText;
                }
                else if (propertyType == typeof(BallisticCoefficient))
                {
                    if (BallisticCoefficient.TryParse(propertyText, CultureInfo.InvariantCulture, out BallisticCoefficient ballisticCoefficient))
                    {
                        propertyValue = ballisticCoefficient;
                    }
                }
                else
                {
                    throw new InvalidOperationException($"The type {propertyType.FullName} of the property {type.FullName}.{propertyName} is not supported");
                }
            }
            return(propertyValue);
        }
Example #12
0
        private void ReadProperty(XmlElement element, Type type, string propertyName, Type propertyType, BXmlPropertyAttribute propertyAttribute, string attributePrefix, Action <object> setProperty, Func <object> getProperty = null)
        {
            bool found = false;

            Type targetType = null;

            if (propertyAttribute.Collection)
            {
                foreach (Type iface in propertyType.GetInterfaces())
                {
                    if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                    {
                        targetType = iface.GetGenericArguments()[0];
                        break;
                    }
                }
                if (targetType == null)
                {
                    throw new InvalidOperationException($"The type of the value {type.FullName}.{propertyName} must implement IEnumerable interface");
                }
            }
            else
            {
                targetType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
            }

            BXmlElementAttribute elementAttribute1 = targetType.GetCustomAttribute <BXmlElementAttribute>();
            BXmlSelectAttribute  selectAttribute   = targetType.GetCustomAttribute <BXmlSelectAttribute>();

            if ((!propertyAttribute.ChildElement || elementAttribute1 == null) && string.IsNullOrEmpty(propertyAttribute.Name))
            {
                throw new InvalidOperationException($"The value of the property {type.FullName}.{propertyName} must have the name specified in the {nameof(BXmlPropertyAttribute)}");
            }

            if ((propertyAttribute.ChildElement || propertyAttribute.Collection) &&
                (elementAttribute1 == null && selectAttribute == null))
            {
                throw new InvalidOperationException($"The type of the property {type.FullName}.{propertyName} must have either {nameof(BXmlElementAttribute)} or {nameof(BXmlSelectAttribute)}");
            }

            if (propertyAttribute.ChildElement)
            {
                string elementToSearch = null;

                if (elementAttribute1 == null && string.IsNullOrEmpty(propertyAttribute.Name))
                {
                    throw new InvalidOperationException($"The value of the property {type.FullName}.{propertyName} must have the name specified in the {nameof(BXmlPropertyAttribute)}");
                }

                elementToSearch = propertyAttribute.Name ?? elementAttribute1?.Name;

                if (!propertyAttribute.FlattenChild)
                {
                    var childElement = FindChildElement(element, elementToSearch);

                    if (childElement != null)
                    {
                        object propertyValue;
                        if (elementAttribute1 != null)
                        {
                            propertyValue = Deserialize(childElement, targetType);
                        }
                        else
                        {
                            propertyValue = Deserialize(childElement, selectAttribute.Options);
                        }

                        setProperty(propertyValue);
                        found = true;
                    }
                }
                else
                {
                    string prefix = $"{elementToSearch}-";
                    bool   any    = false;
                    for (int i = 0; !any && i < element.Attributes.Count; i++)
                    {
                        if (element.Attributes[i].Name.StartsWith(prefix))
                        {
                            any = true;
                        }
                    }

                    if (any)
                    {
                        object propertyValue = Deserialize(element, targetType, elementToSearch);
                        setProperty(propertyValue);
                        found = true;
                    }
                }
            }
            else if (propertyAttribute.Collection)
            {
                object collection = null;
                if (setProperty != null)
                {
                    if (propertyType.IsArray)
                    {
                        collection = Activator.CreateInstance(typeof(List <>).MakeGenericType(targetType));
                    }
                    else
                    {
                        collection = Activator.CreateInstance(propertyType);
                    }
                }
                else
                {
                    if (getProperty != null)
                    {
                        collection = getProperty();
                    }
                    if (collection == null)
                    {
                        throw new InvalidOperationException($"The value of the property {type.FullName}.{propertyName} has no set accessor and is not initialized by default");
                    }
                }

                MethodInfo method = collection.GetType().GetMethod("Add", new Type[] { targetType });
                if (method == null)
                {
                    throw new InvalidOperationException($"The type of the property {type.FullName}.{propertyName} has no Add({targetType.FullName}) method");
                }

                var collectionElement = FindChildElement(element, propertyAttribute.Name);
                if (collectionElement != null)
                {
                    object[] parameters = new object[] { null };
                    foreach (XmlNode node in collectionElement.ChildNodes)
                    {
                        if (node is XmlElement childElement)
                        {
                            if (elementAttribute1 != null)
                            {
                                parameters[0] = Deserialize(childElement, targetType);
                            }
                            else
                            {
                                parameters[0] = Deserialize(childElement, selectAttribute.Options);
                            }

                            method.Invoke(collection, parameters);
                        }
                    }

                    if (setProperty != null)
                    {
                        if (propertyType.IsArray)
                        {
                            collection = collection.GetType().GetMethod("ToArray", new Type[] { }).Invoke(collection, Array.Empty <object>());
                        }
                        setProperty(collection);
                    }

                    found = true;
                }
            }
            else
            {
                object propertyValue = ReadAttribute(type, element, propertyName, propertyType, propertyAttribute, attributePrefix);
                if (propertyValue != null)
                {
                    setProperty(propertyValue);
                    found = true;
                }
            }

            if (!found && !propertyAttribute.Optional)
            {
                throw new InvalidOperationException($"The value of the property {type.FullName}.{propertyName} is not found but the property is not optional");
            }
        }