Add documentation
This commit is contained in:
1 parent
a318ce12fa
commit
7188208b6b
9 files changed
+330
-135
No files matched your search
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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<=x<=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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user