How to serialize a combo box object internally in C # using XElement?
I have an 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
these objects:
Dictionary<string, MyObject> MyObjectsDic = new Dictionary<string, MyObject>();
And the serializer for it is 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 uses abstract Dictionary
as an argument and I need to convert MyObjectsDic
manually. Maybe I am wrong here.
ToXml("MyFile.xml", "MyObjects", MyObjectsDic.ToDictionary(p => p.Key, p => (object)p.Value));
I used this tip to make a serializer. This works well, but I need to add a new member to MyObject
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 this list is serialized to a file like
<Codes>Code1Code2<Codes/>
No space or separator. And I don't know how to make it more readable without changes to the serializer and without adding new odd code. The only idea I got is to store the already prepared string in MyObject instead of List <...>. It's not elegant, but simple and works. I do not read this data, I just write and save it as a log to a file.
Or do I need to change my such cool serializer?
Upd.
I used the solution below, but I am getting an exception on Windows XP. It works well on other OSes. I changed the code to be a helper and not an extension of the class.
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 is different framework versions or some other religious issues in XP ... Unfortunately, I cannot install any other software or .Net version into production.
source to share
Instead of trying to use reflection to manually serialize your class MyObject
, you can use the following methods XmlSerializer
to serialize the dictionary values ββdirectly to XElement
, then specify 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 results in correct serialization of all fields and properties MyObject
. Using this, the resulting XML looks like this:
<MyObjects>
<Item Object="Obj1">
<Str1>Test object</Str1>
<E1>Unknown</E1>
<Done>false</Done>
<Codes>
<Enum2>Code1</Enum2>
<Enum2>Code2</Enum2>
</Codes>
</Item>
</MyObjects>
source to share