I am trying to write a save routine for my application where several parts of the application add items to a Dictionary and then the save function writes them to a XML file. The open routine needs to read those files and re-populate the Dictionary and I can then place those objects back into my application. I am struggling with the de-serialization of the routine I have now. My save routine is as follows
XmlDocument xmlDoc = new XmlDocument();
// Write down the XML declaration
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
// Create the root element
XmlElement rootNode = xmlDoc.CreateElement("TireStudy");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
xmlDoc.AppendChild(rootNode);
foreach (var saveItem in _SaveItems)
{
XPathNavigator nav = rootNode.CreateNavigator();
using (var writer = nav.AppendChild())
{
var serializer = new XmlSerializer(saveItem.Value.GetType());
writer.WriteWhitespace("");
serializer.Serialize(writer, saveItem.Value);
writer.Close();
}
}
xmlDoc.Save(fileName);
This routine works to create a file, but I would like the key value of the dictionary to be saved in the file as well and I am not sure how to de-serialize the file this creates because I do not know the types of the objects before I read them.
Part 2 (I hate adding new parts to a question, but I don't see a better way to address the problems going forward)
I now have the following code,
var knownTypes = new List<Type>
{
typeof(ObservableCollection<string>),
typeof(ObservableCollection<Segments>),
typeof(Segments),
typeof(List<string>)
};
var serialized = _SaveItems.Serialize(knownTypes);
but I get the following exception
Type 'System.Collections.Generic.List`1[System.String]' cannot be added to list of known types since another type 'System.Collections.ObjectModel.ObservableCollection`1[System.String]' with the same data contract name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring' is already present. If there are different collections of a particular type - for example, List<Test> and Test[], they cannot both be added as known types. Consider specifying only one of these types for addition to the known types list.
If I delete either the typeof(ObservableCollection) or the typeof(List) it exceptions complaining it needs the one I deleted.
You could use DataContractSerializer
as explained in this post but you may have to pass the known types as a parameter to the serializer to support nested object
typed classes:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
public static class SerializationExtensions
{
public static string Serialize<T>(this T obj, IEnumerable<Type> knownTypes)
{
var serializer = new DataContractSerializer(obj.GetType(), knownTypes);
using (var writer = new StringWriter())
using (var stm = new XmlTextWriter(writer))
{
serializer.WriteObject(stm, obj);
return writer.ToString();
}
}
public static T Deserialize<T>(this string serialized, IEnumerable<Type> knownTypes)
{
var serializer = new DataContractSerializer(typeof(T), knownTypes);
using (var reader = new StringReader(serialized))
using (var stm = new XmlTextReader(reader))
{
return (T)serializer.ReadObject(stm);
}
}
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
}
public class CodedAddress
{
public int CountryCode { get; set; }
public int CityCode { get; set; }
}
class Program
{
static void Main(string[] args)
{
var persons1 = new Dictionary<string, Address>();
persons1.Add("John Smith", new Address { Country = "US", City = "New York" });
persons1.Add("Jean Martin", new Address { Country = "France", City = "Paris" });
// no need to provide known types to the serializer
var serializedPersons1 = persons1.Serialize(null);
var deserializedPersons1 = serializedPersons1.Deserialize<Dictionary<string, Address>>(null);
var persons2 = new Dictionary<string, object>();
persons2.Add("John Smith", new Address { Country = "US", City = "New York" });
persons2.Add("Jean Martin", new CodedAddress { CountryCode = 33, CityCode = 75 });
// must provide known types to the serializer
var knownTypes = new List<Type> { typeof(Address), typeof(CodedAddress) };
var serializedPersons2 = persons2.Serialize(knownTypes);
var deserializedPersons2 = serializedPersons2.Deserialize<Dictionary<string, object>>(knownTypes);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With