From 9aa9ff9291011dc7a09dd5a886d2d00a6f79a26f Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sat, 25 Oct 2014 00:45:34 +0200 Subject: [PATCH] Implement caching and extension methods --- VocaluxeLib/Xml/CMyXmlDeserializer.cs | 107 +++++++++++++++++++------- 1 file changed, 80 insertions(+), 27 deletions(-) diff --git a/VocaluxeLib/Xml/CMyXmlDeserializer.cs b/VocaluxeLib/Xml/CMyXmlDeserializer.cs index ccf2e6bd..69a35c2b 100644 --- a/VocaluxeLib/Xml/CMyXmlDeserializer.cs +++ b/VocaluxeLib/Xml/CMyXmlDeserializer.cs @@ -25,6 +25,8 @@ namespace VocaluxeLib.Xml { public string Name; public FieldInfo Info; + public object DefaultValue; + public bool HasDefaultValue; public bool IsList; //List with child elements () public bool IsEmbeddedList; //List w/o child elements() public bool IsNullable; @@ -79,67 +81,119 @@ namespace VocaluxeLib.Xml } #endregion Debug Helpers - private static bool _HasAttribute(this FieldInfo field, Type attributeType) + private static bool _HasAttribute(this FieldInfo field) { - return field.GetCustomAttributes(attributeType, false).Length > 0; + return field.GetCustomAttributes(typeof(T), false).Length > 0; } + private static T _GetAttribute(this ICustomAttributeProvider field) where T : class + { + object[] attributes = field.GetCustomAttributes(typeof(T), false); + return attributes.Length == 0 ? null : (T)attributes[0]; + } + + private static bool _IsList(this Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>); + } + + private static bool _IsList(this FieldInfo field) + { + return field.FieldType._IsList(); + } + + private static readonly Dictionary> _CacheFieldAttributes = new Dictionary>(); + private static readonly Dictionary> _CacheFieldFields = new Dictionary>(); + private static readonly Dictionary _CacheTypeName = new Dictionary(); + private static List _GetFields(Type type, bool attributes) { - List result = new List(); + List result; + if (attributes && _CacheFieldAttributes.TryGetValue(type, out result) || + !attributes && _CacheFieldFields.TryGetValue(type, out result)) + return result; + result = new List(); FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in fields) { - if (field._HasAttribute(typeof(XmlIgnoreAttribute))) + if (field._HasAttribute()) continue; - object[] attElement = field.GetCustomAttributes(typeof(XmlAttributeAttribute), false); - if (attElement.Length > 0 != attributes) + XmlAttributeAttribute attribute = field._GetAttribute(); + if (attribute != null != attributes) continue; SFieldInfo info = new SFieldInfo {Info = field}; - if (attElement.Length > 0) - info.Name = ((XmlAttributeAttribute)attElement[0]).AttributeName; + if (attribute != null) + info.Name = attribute.AttributeName; else { - attElement = field.GetCustomAttributes(typeof(XmlElementAttribute), false); - if (attElement.Length > 0) - info.Name = ((XmlElementAttribute)attElement[0]).ElementName; + XmlElementAttribute element = field._GetAttribute(); + if (element != null) + info.Name = element.ElementName; + else + { + XmlArrayAttribute array = field._GetAttribute(); + if (array != null) + { + Debug.Assert(field._IsList()); + info.Name = array.ElementName; + info.IsList = true; + } + } } if (string.IsNullOrEmpty(info.Name)) info.Name = field.Name; + if (field.FieldType.IsGenericType) { - if (field.FieldType.GetGenericTypeDefinition() == typeof(List<>)) + if (field._IsList()) { - attElement = field.GetCustomAttributes(typeof(XmlArrayAttribute), false); - if (attElement.Length > 0) - info.IsList = true; - else + if (!info.IsList) + { + Debug.Assert(!field._HasAttribute(), "A field cannot have an XmlElement- and XmlArray-Attribute"); info.IsEmbeddedList = true; + } } else if (field.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) info.IsNullable = true; info.SubType = field.FieldType.GetGenericArguments()[0]; } - if (field._HasAttribute(typeof(XmlNormalizedAttribute))) + if (field._HasAttribute()) { Debug.Assert(field.FieldType == typeof(float) || (info.IsNullable && info.SubType == typeof(float)), "Only floats can be normalized"); info.IsNormalized = true; } + DefaultValueAttribute defAttr = field._GetAttribute(); + if (defAttr != null) + { + Debug.Assert(!field._IsList(), "Lists cannot have a default value"); + info.HasDefaultValue = true; + info.DefaultValue = defAttr.Value; + } result.Add(info); } + if (attributes) + _CacheFieldAttributes.Add(type, result); + else + _CacheFieldFields.Add(type, result); return result; } private static string _GetTypeName(Type type) { - object[] att = type.GetCustomAttributes(typeof(XmlTypeAttribute), false); - if (att.Length > 0) + string name; + if (_CacheTypeName.TryGetValue(type, out name)) + return name; + XmlTypeAttribute att = type._GetAttribute(); + if (att != null) { - string name = ((XmlTypeAttribute)att[0]).TypeName; - if (!string.IsNullOrEmpty(name)) - return name; + name = att.TypeName; + if (string.IsNullOrEmpty(name)) + name = type.Name; } - return type.Name; + else + name = type.Name; + _CacheTypeName.Add(type, name); + return name; } private static object _GetValue(XmlNode node, Type type) @@ -160,7 +214,7 @@ namespace VocaluxeLib.Xml return node.InnerText; if (type.IsPrimitive) return _GetPrimitiveValue(node, type); - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + if (type._IsList()) { Type subType = type.GetGenericArguments()[0]; String subName = _GetTypeName(subType); @@ -214,10 +268,9 @@ namespace VocaluxeLib.Xml _AddList(result, field, new List()); return true; } - object[] defAtt = field.Info.GetCustomAttributes(typeof(DefaultValueAttribute), false); - if (defAtt.Length == 0) + if (!field.HasDefaultValue) return field.IsNullable; - field.Info.SetValue(result, ((DefaultValueAttribute)defAtt[0]).Value); + field.Info.SetValue(result, field.DefaultValue); return true; }