Add documentation

This commit is contained in:
Flamefire committed 2014-10-30 19:21:28 +01:00
1 parent a318ce12fa
commit 7188208b6b
9 files changed
+330 -135

No files matched your search

+2 -2
View File
@@ -78,8 +78,8 @@ namespace Vocaluxe.Base
foreach (string file in files)
{
CPlaylistFile playlist = new CPlaylistFile();
if(playlist._Load(file))
_Playlists.Add(playlist);
if (playlist._Load(file))
_Playlists.Add(playlist);
}
}
+1 -1
View File
@@ -149,7 +149,7 @@ namespace VocaluxeLib.Menu
_ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/Reflection/Space", ref ReflectionSpace);
_ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/Reflection/Height", ref ReflectionHeight);
_Theme.Reflection = new SReflection( ReflectionHeight, ReflectionSpace);
_Theme.Reflection = new SReflection(ReflectionHeight, ReflectionSpace);
}
else
{
+1 -1
View File
@@ -52,7 +52,7 @@ namespace VocaluxeLib.Menu
CSong song = CBase.Songs.GetSongByID(SongID);
if (song == null)
throw new Exception("Can't find Song. This should never happen!");
return new SPlaylistSong{Artist = song.Artist, Title = song.Title, GameMode = GameMode};
return new SPlaylistSong {Artist = song.Artist, Title = song.Title, GameMode = GameMode};
}
}
+1
View File
@@ -145,6 +145,7 @@
<Compile Include="Utils\CWavFile.cs" />
<Compile Include="Utils\Player\CSongPlayer.cs" />
<Compile Include="Utils\Player\CSoundPlayer.cs" />
<Compile Include="Xml\SFieldInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
+61 -51
View File
@@ -1,4 +1,21 @@
using System;
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
@@ -9,6 +26,9 @@ using System.Xml.Serialization;
namespace VocaluxeLib.Xml
{
// ReSharper disable InconsistentNaming
/// <summary>
/// Attribute containing an alternative name in the xml files during deserialization
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class XmlAltNameAttribute : Attribute
{
@@ -20,9 +40,15 @@ namespace VocaluxeLib.Xml
}
}
/// <summary>
/// Attribute for float fields to enforce normalized (0&lt;=x&lt;=1) values
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class XmlNormalizedAttribute : Attribute {}
/// <summary>
/// Attribute for int fields to enforce values in the given range
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class XmlRangedAttribute : Attribute
{
@@ -38,58 +64,9 @@ namespace VocaluxeLib.Xml
// ReSharper restore InconsistentNaming
public struct SFieldInfo
{
private readonly FieldInfo _Field;
private readonly PropertyInfo _Property;
public Type Type
{
get { return _Field != null ? _Field.FieldType : _Property.PropertyType; }
}
public string Name;
public string AltName;
public object DefaultValue;
public bool HasDefaultValue;
public bool IsAttribute;
public bool IsList; //List with child elements (<List><El/><El/></List>)
public bool IsEmbeddedList; //List w/o child elements(<List/><List/>)
public bool IsDictionary; //List where the element names are the keys
public bool IsByteArray; // Byte arrays w/o XmlArrayAttribute are serialized as Base64-Encoded strings
public bool IsNullable;
public bool IsNormalized;
public XmlRangedAttribute Ranged;
public Type SubType;
public string ArrayItemName;
public SFieldInfo(FieldInfo field)
: this()
{
_Field = field;
}
public SFieldInfo(PropertyInfo property)
: this()
{
_Property = property;
}
public void SetValue(object o, object value)
{
if (_Field != null)
_Field.SetValue(o, value);
else
_Property.SetValue(o, value, new object[] {});
}
public object GetValue(object o)
{
return (_Field != null) ? _Field.GetValue(o) : _Property.GetValue(o, new object[] {});
}
}
public static class CTypeExtensions
{
// Cache for fields to speed up access to common types
private static readonly Dictionary<Type, List<SFieldInfo>> _CacheFields = new Dictionary<Type, List<SFieldInfo>>();
private static readonly Dictionary<Type, String> _CacheTypeName = new Dictionary<Type, string>();
@@ -110,6 +87,11 @@ namespace VocaluxeLib.Xml
return subType.GetTypeName();
}
/// <summary>
/// Fills the struct with information about the field
/// </summary>
/// <param name="info">Struct to fill</param>
/// <param name="field">Field descrived by the struct</param>
private static void _FillInfo(ref SFieldInfo info, MemberInfo field)
{
XmlAttributeAttribute attribute = field.GetAttribute<XmlAttributeAttribute>();
@@ -193,6 +175,11 @@ namespace VocaluxeLib.Xml
}
}
/// <summary>
/// Returns a collection with infos about all fields and properties of the type that can be (xml-)serialized
/// </summary>
/// <param name="type">Type to get information about</param>
/// <returns></returns>
public static IEnumerable<SFieldInfo> GetFieldInfos(this Type type)
{
List<SFieldInfo> result;
@@ -221,11 +208,22 @@ namespace VocaluxeLib.Xml
return result;
}
/// <summary>
/// Returns a collection with infos about all fields and properties of the type that can be (xml-)serialized but limits it to those which are (xml)-nodes or attributes
/// </summary>
/// <param name="type">Type to get information about</param>
/// <param name="attributes">True to return infos about attributes, false for nodes</param>
/// <returns></returns>
public static List<SFieldInfo> GetFields(this Type type, bool attributes)
{
return GetFieldInfos(type).Where(f => f.IsAttribute == attributes).ToList();
}
/// <summary>
/// Gets the (xml)-type name for the type (influenced by XmlTypeAttributes)
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static string GetTypeName(this Type type)
{
string name;
@@ -244,11 +242,23 @@ namespace VocaluxeLib.Xml
return name;
}
/// <summary>
/// Returns true if the field has the attribute
/// </summary>
/// <typeparam name="T">Attribute type</typeparam>
/// <param name="field"></param>
/// <returns></returns>
public static bool HasAttribute<T>(this ICustomAttributeProvider field)
{
return field.GetCustomAttributes(typeof(T), false).Length > 0;
}
/// <summary>
/// Gets the first attribute with the given type or null if none found
/// </summary>
/// <typeparam name="T">Attribute type</typeparam>
/// <param name="field"></param>
/// <returns></returns>
public static T GetAttribute<T>(this ICustomAttributeProvider field) where T : class
{
object[] attributes = field.GetCustomAttributes(typeof(T), false);
+160 -53
View File
@@ -1,4 +1,21 @@
using System;
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -14,6 +31,11 @@ namespace VocaluxeLib.Xml
public class CXmlDeserializer
{
#region Debug Helpers
/// <summary>
/// Returns the xPath from root to the node
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
private string _GetXPath(XmlNode node)
{
StringBuilder builder = new StringBuilder();
@@ -39,6 +61,11 @@ namespace VocaluxeLib.Xml
throw new ArgumentException("Node was not in a document");
}
/// <summary>
/// Returns an index as a string or empty string if the node name is sufficient to identify the node
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private string _FindElementIndex(XmlNode element)
{
XmlNode parentNode = element.ParentNode;
@@ -60,7 +87,15 @@ namespace VocaluxeLib.Xml
}
#endregion Debug Helpers
private object _GetValue(XmlNode node, Type type, string arrayItemName = null, object result = null)
/// <summary>
/// Returns the value if the given node
/// </summary>
/// <param name="node">Node to process</param>
/// <param name="type">Type of the object at that node</param>
/// <param name="subName">Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name</param>
/// <param name="value">If given, no new class is created and value is used instead</param>
/// <returns></returns>
private object _GetValue(XmlNode node, Type type, string subName = null, object value = null)
{
if (type.IsEnum)
{
@@ -83,12 +118,13 @@ namespace VocaluxeLib.Xml
if (!node.HasChildNodes)
return null;
Type subType = type.GetGenericArguments()[0];
return _GetValue(node, subType, arrayItemName, result);
return _GetValue(node, subType, subName, value);
}
if (type.IsList() || type.IsArray)
{
Type subType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];
String subName = arrayItemName ?? subType.GetTypeName();
if (subName == null)
subName = subType.GetTypeName();
subName = subName.ToLowerInvariant();
List<object> subValues = new List<object>();
foreach (XmlNode subNode in node.ChildNodes)
@@ -100,56 +136,64 @@ namespace VocaluxeLib.Xml
object subValue = _GetValue(subNode, subType);
subValues.Add(subValue);
}
if (result == null)
if (value == null)
return _CreateList(type, subValues);
_FillList(result, type, subValues);
return result;
_FillList(value, type, subValues);
return value;
}
if (type.IsDictionary())
{
Type subType = type.GetGenericArguments()[1];
object dict = result ?? Activator.CreateInstance(type);
object dict = value ?? Activator.CreateInstance(type);
MethodInfo add = type.GetMethod("Add");
if (arrayItemName != null)
arrayItemName = arrayItemName.ToLowerInvariant();
if (subName != null)
subName = subName.ToLowerInvariant();
foreach (XmlNode subNode in node.ChildNodes)
{
if (subNode is XmlComment)
continue;
object subValue = _GetValue(subNode, subType);
string subName;
if (arrayItemName != null)
string key;
if (subName != null)
{
if (arrayItemName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(arrayItemName))
throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + arrayItemName);
if (subName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(subName))
throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + subName);
if (subNode.Attributes == null)
throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode));
XmlNode nameAtt = subNode.Attributes.GetNamedItem("name");
if (nameAtt == null)
throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode));
subName = nameAtt.Value;
key = nameAtt.Value;
}
else
subName = subNode.Name;
add.Invoke(dict, new object[] { subName, subValue });
key = subNode.Name;
add.Invoke(dict, new object[] {key, subValue});
}
return dict;
}
object value;
try
if (value == null)
{
value = result ?? Activator.CreateInstance(type);
try
{
value = Activator.CreateInstance(type);
}
catch (Exception)
{
throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")");
}
}
catch (Exception)
{
throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")");
}
_ReadChildNodes(node, ref value, true);
_ReadChildNodes(node, ref value, false);
_ReadChildNodes(node, value, true);
_ReadChildNodes(node, value, false);
return value;
}
/// <summary>
/// Gets the node's value assuming it is a primitive (int,float,...)
/// </summary>
/// <param name="node"></param>
/// <param name="type"></param>
/// <returns></returns>
private object _GetPrimitiveValue(XmlNode node, Type type)
{
object value;
@@ -177,6 +221,12 @@ namespace VocaluxeLib.Xml
return value;
}
/// <summary>
/// Sets the field to its default value if it has one (specified as DefaultValueAttribute or an empty collection if it is an embedded one)
/// </summary>
/// <param name="result"></param>
/// <param name="field"></param>
/// <returns>True if default value was set</returns>
private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field)
{
if (field.IsEmbeddedList)
@@ -190,6 +240,12 @@ namespace VocaluxeLib.Xml
return true;
}
/// <summary>
/// Fills the specified collection (array or list) with the values
/// </summary>
/// <param name="list">List to fill</param>
/// <param name="type">Type of the list</param>
/// <param name="values">Collection of values</param>
private static void _FillList(object list, Type type, ICollection values)
{
if (values.Count <= 0)
@@ -205,23 +261,41 @@ namespace VocaluxeLib.Xml
{
MethodInfo addMethod = type.GetMethod("Add");
foreach (object value in values)
addMethod.Invoke(list, new object[] { value });
addMethod.Invoke(list, new object[] {value});
}
}
/// <summary>
/// Creates a collection (array or list) and fills it with the values
/// </summary>
/// <param name="type">Type of the collection to be created</param>
/// <param name="values">Collection of values</param>
/// <returns>Newly created collection</returns>
private static object _CreateList(Type type, ICollection values)
{
object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] { values.Count });
object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] {values.Count});
_FillList(list, type, values);
return list;
}
private static void _AddList(object result, SFieldInfo listField, ICollection list)
/// <summary>
/// Creates a collection (array or list) and puts it into the specified field
/// </summary>
/// <param name="o">Object which listField belongs to</param>
/// <param name="listField">Field that will contain the list</param>
/// <param name="values">Collection of values that are used to fill the list</param>
private static void _AddList(object o, SFieldInfo listField, ICollection values)
{
listField.SetValue(result, _CreateList(listField.Type, list));
listField.SetValue(o, _CreateList(listField.Type, values));
}
private void _ReadChildNodes(XmlNode parent, ref object result, bool attributes)
/// <summary>
/// Reads childnodes of the given node (either nodes or attributes)
/// </summary>
/// <param name="parent">Node to process</param>
/// <param name="o">Object to put the values in</param>
/// <param name="attributes">True for processing attributes, false for nodes</param>
private void _ReadChildNodes(XmlNode parent, object o, bool attributes)
{
IEnumerable nodes;
if (attributes)
@@ -229,7 +303,7 @@ namespace VocaluxeLib.Xml
else
nodes = parent.ChildNodes;
List<SFieldInfo> fields = result.GetType().GetFields(attributes);
List<SFieldInfo> fields = o.GetType().GetFields(attributes);
if (nodes != null)
{
@@ -258,7 +332,7 @@ namespace VocaluxeLib.Xml
if (field.IsByteArray)
{
field.SetValue(result, Convert.FromBase64String(node.InnerText));
field.SetValue(o, Convert.FromBase64String(node.InnerText));
fields.RemoveAt(curField);
}
else if (field.IsEmbeddedList)
@@ -298,29 +372,35 @@ namespace VocaluxeLib.Xml
")");
}
}
field.SetValue(result, value);
field.SetValue(o, value);
fields.RemoveAt(curField);
}
}
//Add embedded lists
foreach (Tuple<SFieldInfo, List<object>> entry in embLists.Values)
{
_AddList(result, entry.Item1, entry.Item2);
_AddList(o, entry.Item1, entry.Item2);
fields.Remove(entry.Item1);
}
}
foreach (SFieldInfo field in fields)
{
if (!_CheckAndSetDefaultValue(result, field))
if (!_CheckAndSetDefaultValue(o, field))
throw new XmlException("element: " + field.Name + " is missing in " + _GetXPath(parent));
}
}
private T _Deserialize<T>(XmlReader reader, object result) where T : new()
/// <summary>
/// Deserializes the content of read into the given object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader"></param>
/// <param name="o"></param>
/// <returns>Deserialized object</returns>
private T _Deserialize<T>(XmlReader reader, object o) where T : new()
{
if (reader.IsEmptyElement)
return (T)result;
return (T)o;
XmlDocument xDoc = new XmlDocument();
xDoc.Load(reader);
@@ -328,28 +408,42 @@ namespace VocaluxeLib.Xml
throw new XmlException("No root element found!");
try
{
result = _GetValue(xDoc.DocumentElement, typeof(T), typeof(T).GetSubTypeName(), result);
o = _GetValue(xDoc.DocumentElement, o.GetType(), o.GetType().GetSubTypeName(), o);
}
catch (TargetInvocationException e)
{
throw e.InnerException ?? e;
}
return (T)result;
return (T)o;
}
/// <summary>
/// Deserializes the given xml string and returns the resulting object
/// </summary>
/// <typeparam name="T">Type of the object contained in the xml</typeparam>
/// <param name="xml">xml string</param>
/// <returns>New object of type T</returns>
public T DeserializeString<T>(string xml) where T : new()
{
return DeserializeString(xml, new T());
}
/// <summary>
/// Deserializes the given xml string and returns the resulting object<br />
/// Does not create a new object but reuses the given one overwriting its values
/// </summary>
/// <typeparam name="T">Type of the object contained in the xml</typeparam>
/// <param name="xml">xml string</param>
/// <param name="o">Existing object</param>
/// <returns>New object of type T</returns>
public T DeserializeString<T>(string xml, T o) where T : new()
{
var reader = new XmlTextReader(new StringReader(xml))
{
WhitespaceHandling = WhitespaceHandling.Significant,
Normalization = true,
XmlResolver = null
};
{
WhitespaceHandling = WhitespaceHandling.Significant,
Normalization = true,
XmlResolver = null
};
try
{
return _Deserialize<T>(reader, o);
@@ -360,21 +454,35 @@ namespace VocaluxeLib.Xml
}
}
/// <summary>
/// Deserializes the given file and returns the resulting object
/// </summary>
/// <typeparam name="T">Type of the object contained in the xml</typeparam>
/// <param name="filePath">Full path to the file</param>
/// <returns>New object of type T</returns>
public T Deserialize<T>(string filePath) where T : new()
{
return Deserialize(filePath, new T());
}
/// <summary>
/// Deserializes the given file and returns the resulting object<br />
/// Does not create a new object but reuses the given one overwriting its values
/// </summary>
/// <typeparam name="T">Type of the object contained in the xml</typeparam>
/// <param name="filePath">Full path to the file</param>
/// <param name="o">Existing object</param>
/// <returns>New object of type T</returns>
public T Deserialize<T>(string filePath, T o) where T : new()
{
if (!File.Exists(filePath))
throw new FileNotFoundException(filePath);
var reader = new XmlTextReader(filePath)
{
WhitespaceHandling = WhitespaceHandling.Significant,
Normalization = true,
XmlResolver = null
};
{
WhitespaceHandling = WhitespaceHandling.Significant,
Normalization = true,
XmlResolver = null
};
try
{
return _Deserialize<T>(reader, o);
@@ -384,6 +492,5 @@ namespace VocaluxeLib.Xml
reader.Close();
}
}
}
}
}
+81 -24
View File
@@ -1,4 +1,21 @@
using System;
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
@@ -17,6 +34,11 @@ namespace VocaluxeLib.Xml
private readonly GetCommentDelegate _GetCommentCallback;
private readonly bool _WriteDefaults;
/// <summary>
/// Creates a new serializer
/// </summary>
/// <param name="writeDefaults">When true, also nodes with default values will be written</param>
/// <param name="getCommentCallback">Callback that is called for each node and should return a string that will be used as a comment</param>
public CXmlSerializer(bool writeDefaults = false, GetCommentDelegate getCommentCallback = null)
{
_WriteDefaults = writeDefaults;
@@ -33,7 +55,17 @@ namespace VocaluxeLib.Xml
ConformanceLevel = ConformanceLevel.Document
};
private void _WriteNode(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null)
/// <summary>
/// Writes a value as a node or attribute
/// </summary>
/// <param name="writer">XmlWriter to use</param>
/// <param name="name">Name of the node/attribute</param>
/// <param name="type">Type of the value</param>
/// <param name="value">Object to write</param>
/// <param name="isAttribute">When true, value will be written as an attribute to the currently open node, otherwhise it will create a new node</param>
/// <param name="arrayItemName">>Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name</param>
/// <param name="nameAttribute">If set, an attribute 'name' with this value will be written</param>
private void _WriteValue(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null)
{
if (!isAttribute && _GetCommentCallback != null)
{
@@ -65,7 +97,7 @@ namespace VocaluxeLib.Xml
}
}
else if (type.IsNullable())
_WriteNode(writer, name, type.GetGenericArguments()[0], value, isAttribute, arrayItemName, nameAttribute);
_WriteValue(writer, name, type.GetGenericArguments()[0], value, isAttribute, arrayItemName, nameAttribute);
else if (type.IsList() || type.IsArray)
{
Debug.Assert(!isAttribute, "Lists cannot be attributes");
@@ -76,7 +108,7 @@ namespace VocaluxeLib.Xml
String subName = arrayItemName ?? subType.GetTypeName();
IEnumerable list = (IEnumerable)value;
foreach (object subValue in list)
_WriteNode(writer, subName, subType, subValue, false);
_WriteValue(writer, subName, subType, subValue, false);
writer.WriteEndElement();
}
else if (type.IsDictionary())
@@ -101,7 +133,7 @@ namespace VocaluxeLib.Xml
subName = arrayItemName;
subNameAttribute = (string)entry.Key;
}
_WriteNode(writer, subName, subType, entry.Value, false, null, subNameAttribute);
_WriteValue(writer, subName, subType, entry.Value, false, null, subNameAttribute);
}
writer.WriteEndElement();
}
@@ -112,12 +144,17 @@ namespace VocaluxeLib.Xml
if (nameAttribute != null)
writer.WriteAttributeString("name", nameAttribute);
if (value != null)
_WriteChildNodes(writer, value);
_WriteFields(writer, value);
writer.WriteEndElement();
}
}
private void _WriteChildNodes(XmlWriter writer, object o)
/// <summary>
/// Writes the fields of the given object, does not write the node tags itself
/// </summary>
/// <param name="writer">XmlWriter to use</param>
/// <param name="o">Object to process</param>
private void _WriteFields(XmlWriter writer, object o)
{
IEnumerable<SFieldInfo> fields = o.GetType().GetFieldInfos();
foreach (SFieldInfo field in fields)
@@ -129,33 +166,41 @@ namespace VocaluxeLib.Xml
{
IEnumerable values = (IEnumerable)value;
foreach (object subValue in values)
_WriteNode(writer, field.Name, field.SubType, subValue, field.IsAttribute);
_WriteValue(writer, field.Name, field.SubType, subValue, field.IsAttribute);
}
else if (field.IsByteArray)
writer.WriteElementString(field.Name, Convert.ToBase64String((byte[])value));
else
_WriteNode(writer, field.Name, field.Type, value, field.IsAttribute, field.ArrayItemName);
_WriteValue(writer, field.Name, field.Type, value, field.IsAttribute, field.ArrayItemName);
}
}
private void _Serialize(object o, XmlWriter writer)
/// <summary>
/// Serializes the given object using the writer
/// </summary>
/// <param name="writer">XmlWriter to use</param>
/// <param name="o">Object to serialize</param>
/// <param name="rootNodeName">(optional) Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root")</param>
private void _Serialize(XmlWriter writer, object o, string rootNodeName)
{
XmlRootAttribute root = o.GetType().GetAttribute<XmlRootAttribute>();
string name;
if (root != null && !string.IsNullOrEmpty(root.ElementName))
name = root.ElementName;
else
if (string.IsNullOrEmpty(rootNodeName))
{
XmlTypeAttribute typeAtt = o.GetType().GetAttribute<XmlTypeAttribute>();
if (typeAtt != null && !string.IsNullOrEmpty(typeAtt.TypeName))
name = typeAtt.TypeName;
XmlRootAttribute root = o.GetType().GetAttribute<XmlRootAttribute>();
if (root != null && !string.IsNullOrEmpty(root.ElementName))
rootNodeName = root.ElementName;
else
name = "root";
{
XmlTypeAttribute typeAtt = o.GetType().GetAttribute<XmlTypeAttribute>();
if (typeAtt != null && !string.IsNullOrEmpty(typeAtt.TypeName))
rootNodeName = typeAtt.TypeName;
else
rootNodeName = "root";
}
}
try
{
writer.WriteStartDocument();
_WriteNode(writer, name, o.GetType(), o, false, o.GetType().GetSubTypeName());
_WriteValue(writer, rootNodeName, o.GetType(), o, false, o.GetType().GetSubTypeName());
writer.WriteEndDocument();
}
finally
@@ -164,17 +209,29 @@ namespace VocaluxeLib.Xml
}
}
public void Serialize(string filePath, object o)
/// <summary>
/// Serializes the given object to the file
/// </summary>
/// <param name="filePath">Full path to file</param>
/// <param name="o">Object to serialize</param>
/// <param name="rootNodeName">Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root")</param>
public void Serialize(string filePath, object o, string rootNodeName = null)
{
using (XmlWriter writer = XmlWriter.Create(filePath, _XMLSettings))
_Serialize(o, writer);
_Serialize(writer, o, rootNodeName);
}
public string Serialize(object o)
/// <summary>
/// Serializes the given object and returns the resulting xml as a string
/// </summary>
/// <param name="o">Object to serialize</param>
/// <param name="rootNodeName">Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root")</param>
/// <returns>Serialized object</returns>
public string Serialize(object o, string rootNodeName = null)
{
MemoryStream result = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(result, _XMLSettings))
_Serialize(o, writer);
_Serialize(writer, o, rootNodeName);
result.Position = 0;
return new StreamReader(result).ReadToEnd();
}
+18 -1
View File
@@ -1,4 +1,21 @@
using System.ComponentModel;
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System.ComponentModel;
using System.Xml.Serialization;
namespace VocaluxeLib
+5 -2
View File
@@ -420,7 +420,8 @@ namespace VocaluxeTests
[TestMethod]
public void TestRealFiles()
{
Type[] types = new Type[] {typeof(SThemeCover), typeof(CConfig.SConfig), typeof(SThemeScreen), typeof(SDefaultFonts), typeof(SSkin), typeof(STheme)};
Type[] types = new Type[]
{typeof(SThemeCover), typeof(CConfig.SConfig), typeof(SThemeScreen), typeof(SDefaultFonts), typeof(SSkin), typeof(STheme), typeof(Dictionary<string, string>)};
string filePath = Path.Combine(new string[] {AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "TestXmlFiles"});
foreach (Type type in types)
{
@@ -437,7 +438,9 @@ namespace VocaluxeTests
}
Assert.IsInstanceOfType(foo, type, "Wrong type with " + type.Name);
var ser = new CXmlSerializer(type == typeof(CConfig.SConfig));
string newXml = ser.Serialize(foo);
string newXml = ser.Serialize(type == typeof(Dictionary<string, string>) ? "resources" : foo);
// Typename will be uppercase but input is lowercase
newXml = newXml.Replace("<String", "<string").Replace("</String", "</string");
string oldXml = File.ReadAllText(xmlPath);
Assert.AreEqual(oldXml, newXml, "Error with " + type.Name);
}