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); }
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); }
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"); } }
/// <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"); }
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); } }
/// <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"); } }
/// <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); }
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"); } }