I have object with members of different types like this:
public class MyObject
{
public string Str1 = string.Empty;
public MyEnums.Enum1 E1 = MyEnums.Enum1.Unknown;
public bool Done = false;
};
I have Dictionary
of these objects:
Dictionary<string, MyObject> MyObjectsDic = new Dictionary<string, MyObject>();
And serializer for it like this:
public static void ToXml(string file, string collectionName, Dictionary<string, object> collection)
{
XElement root = new XElement(collectionName);
root.Add(collection.Select(x => new XElement("Item", new XAttribute("Object", x.Key),
x.Value.GetType().GetFields().Select(f => new XElement(f.Name, f.GetValue(x.Value))))));
root.Save(file);
}
The serializer tooks abstract Dictionary
as argument and I need to convert my MyObjectsDic
manually. May be I mistaken here.
ToXml("MyFile.xml", "MyObjects", MyObjectsDic.ToDictionary(p => p.Key, p => (object)p.Value));
I used this advice to make the serializer. It works good, but I need to add to MyObject new member
List<MyEnums.Enum2> Codes = new List<MyEnums.Enum2>();
And store some values here
var a = new MyObject {...};
a.Codes.Add(MyEnums.Enum2.Code1);
a.Codes.Add(MyEnums.Enum2.Code2);
MyObjectsDic.Add("Obj1", a);
But these list is serialized into file like
<Codes>Code1Code2<Codes/>
Without any space or delimiter. And I don't know how to make it more readable without modifications in serializer and without adding new odd code. The only idea I got is to keep already prepared string in MyObject instead of List<...>. It isn't graceful, but simple and works. I don't read these data, just only write and save as log into file.
Or I need to change my so cool serializer?
Upd.
I used the solution below, but I'm receiving an exception on Windows XP. On other OS's it works good. I modified code to make it like helper not an class extension.
Exception during dumping MyObjectsDic: There was an error reflecting type 'MyObject'.
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type)
at MyXmlSerializerHelper.SerializeToXElement[T](T obj, XmlSerializer serializer, Boolean omitStandardNamespaces) in MyXmlSerializerHelper.cs:line 16
at MyXmlSerializerHelper. <SerializeToFile>b__0[T](KeyValuePair'2 x) in MyXmlSerializerHelper.cs:line 5
The only idea I have - different versions of framework or some other religious issues on XP... Unfortunately, I can't install any other software or .Net version in production.
Rather than attempting to use reflection to manually serialize your MyObject
class, you can use XmlSerializer
to serialize your dictionary values directly to an XElement
using the following methods, then include the result in the element tree you are building:
public static class XObjectExtensions
{
public static XElement SerializeToXElement<T>(this IDictionary<string, T> collection, string collectionName)
{
return new XElement(collectionName, collection.Select(x => new XElement("Item", new XAttribute("Object", x.Key), x.Value.SerializeToXElement().Elements())));
}
public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = true)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
(ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns);
}
var element = doc.Root;
if (element != null)
element.Remove();
return element;
}
}
This automatically causes all fields and properties of MyObject
to be serialized properly. Using this, the resulting XML will look like:
<MyObjects> <Item Object="Obj1"> <Str1>Test object</Str1> <E1>Unknown</E1> <Done>false</Done> <Codes> <Enum2>Code1</Enum2> <Enum2>Code2</Enum2> </Codes> </Item> </MyObjects>