Implement caching and extension methods

This commit is contained in:
Flamefire committed 2014-10-25 00:45:34 +02:00
1 parent 2452306e6c
commit 9aa9ff9291
1 file changed
+80 -27
+80 -27
View File
@@ -25,6 +25,8 @@ namespace VocaluxeLib.Xml
{ {
public string Name; public string Name;
public FieldInfo Info; public FieldInfo Info;
public object DefaultValue;
public bool HasDefaultValue;
public bool IsList; //List with child elements (<List><El/><El/></List>) public bool IsList; //List with child elements (<List><El/><El/></List>)
public bool IsEmbeddedList; //List w/o child elements(<List/><List/>) public bool IsEmbeddedList; //List w/o child elements(<List/><List/>)
public bool IsNullable; public bool IsNullable;
@@ -79,67 +81,119 @@ namespace VocaluxeLib.Xml
} }
#endregion Debug Helpers #endregion Debug Helpers
private static bool _HasAttribute(this FieldInfo field, Type attributeType) private static bool _HasAttribute<T>(this FieldInfo field)
{ {
return field.GetCustomAttributes(attributeType, false).Length > 0; return field.GetCustomAttributes(typeof(T), false).Length > 0;
} }
private static T _GetAttribute<T>(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<Type, List<SFieldInfo>> _CacheFieldAttributes = new Dictionary<Type, List<SFieldInfo>>();
private static readonly Dictionary<Type, List<SFieldInfo>> _CacheFieldFields = new Dictionary<Type, List<SFieldInfo>>();
private static readonly Dictionary<Type, String> _CacheTypeName = new Dictionary<Type, string>();
private static List<SFieldInfo> _GetFields(Type type, bool attributes) private static List<SFieldInfo> _GetFields(Type type, bool attributes)
{ {
List<SFieldInfo> result = new List<SFieldInfo>(); List<SFieldInfo> result;
if (attributes && _CacheFieldAttributes.TryGetValue(type, out result) ||
!attributes && _CacheFieldFields.TryGetValue(type, out result))
return result;
result = new List<SFieldInfo>();
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo field in fields) foreach (FieldInfo field in fields)
{ {
if (field._HasAttribute(typeof(XmlIgnoreAttribute))) if (field._HasAttribute<XmlIgnoreAttribute>())
continue; continue;
object[] attElement = field.GetCustomAttributes(typeof(XmlAttributeAttribute), false); XmlAttributeAttribute attribute = field._GetAttribute<XmlAttributeAttribute>();
if (attElement.Length > 0 != attributes) if (attribute != null != attributes)
continue; continue;
SFieldInfo info = new SFieldInfo {Info = field}; SFieldInfo info = new SFieldInfo {Info = field};
if (attElement.Length > 0) if (attribute != null)
info.Name = ((XmlAttributeAttribute)attElement[0]).AttributeName; info.Name = attribute.AttributeName;
else else
{ {
attElement = field.GetCustomAttributes(typeof(XmlElementAttribute), false); XmlElementAttribute element = field._GetAttribute<XmlElementAttribute>();
if (attElement.Length > 0) if (element != null)
info.Name = ((XmlElementAttribute)attElement[0]).ElementName; info.Name = element.ElementName;
else
{
XmlArrayAttribute array = field._GetAttribute<XmlArrayAttribute>();
if (array != null)
{
Debug.Assert(field._IsList());
info.Name = array.ElementName;
info.IsList = true;
}
}
} }
if (string.IsNullOrEmpty(info.Name)) if (string.IsNullOrEmpty(info.Name))
info.Name = field.Name; info.Name = field.Name;
if (field.FieldType.IsGenericType) if (field.FieldType.IsGenericType)
{ {
if (field.FieldType.GetGenericTypeDefinition() == typeof(List<>)) if (field._IsList())
{ {
attElement = field.GetCustomAttributes(typeof(XmlArrayAttribute), false); if (!info.IsList)
if (attElement.Length > 0) {
info.IsList = true; Debug.Assert(!field._HasAttribute<XmlArrayAttribute>(), "A field cannot have an XmlElement- and XmlArray-Attribute");
else
info.IsEmbeddedList = true; info.IsEmbeddedList = true;
}
} }
else if (field.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) else if (field.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
info.IsNullable = true; info.IsNullable = true;
info.SubType = field.FieldType.GetGenericArguments()[0]; info.SubType = field.FieldType.GetGenericArguments()[0];
} }
if (field._HasAttribute(typeof(XmlNormalizedAttribute))) if (field._HasAttribute<XmlNormalizedAttribute>())
{ {
Debug.Assert(field.FieldType == typeof(float) || (info.IsNullable && info.SubType == typeof(float)), "Only floats can be normalized"); Debug.Assert(field.FieldType == typeof(float) || (info.IsNullable && info.SubType == typeof(float)), "Only floats can be normalized");
info.IsNormalized = true; info.IsNormalized = true;
} }
DefaultValueAttribute defAttr = field._GetAttribute<DefaultValueAttribute>();
if (defAttr != null)
{
Debug.Assert(!field._IsList(), "Lists cannot have a default value");
info.HasDefaultValue = true;
info.DefaultValue = defAttr.Value;
}
result.Add(info); result.Add(info);
} }
if (attributes)
_CacheFieldAttributes.Add(type, result);
else
_CacheFieldFields.Add(type, result);
return result; return result;
} }
private static string _GetTypeName(Type type) private static string _GetTypeName(Type type)
{ {
object[] att = type.GetCustomAttributes(typeof(XmlTypeAttribute), false); string name;
if (att.Length > 0) if (_CacheTypeName.TryGetValue(type, out name))
return name;
XmlTypeAttribute att = type._GetAttribute<XmlTypeAttribute>();
if (att != null)
{ {
string name = ((XmlTypeAttribute)att[0]).TypeName; name = att.TypeName;
if (!string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
return 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) private static object _GetValue(XmlNode node, Type type)
@@ -160,7 +214,7 @@ namespace VocaluxeLib.Xml
return node.InnerText; return node.InnerText;
if (type.IsPrimitive) if (type.IsPrimitive)
return _GetPrimitiveValue(node, type); return _GetPrimitiveValue(node, type);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) if (type._IsList())
{ {
Type subType = type.GetGenericArguments()[0]; Type subType = type.GetGenericArguments()[0];
String subName = _GetTypeName(subType); String subName = _GetTypeName(subType);
@@ -214,10 +268,9 @@ namespace VocaluxeLib.Xml
_AddList(result, field, new List<object>()); _AddList(result, field, new List<object>());
return true; return true;
} }
object[] defAtt = field.Info.GetCustomAttributes(typeof(DefaultValueAttribute), false); if (!field.HasDefaultValue)
if (defAtt.Length == 0)
return field.IsNullable; return field.IsNullable;
field.Info.SetValue(result, ((DefaultValueAttribute)defAtt[0]).Value); field.Info.SetValue(result, field.DefaultValue);
return true; return true;
} }