I have an ArrayList which stores a custom object. I want to serialize that ArrayList to a string so I can save it inside the Application settings.
This question looks to resolve it, but is in java. And I am not smart with XML, so could someone help out?
Serialize an ArrayList of Date object type
I have my ArrayList setup:
...
MyObject tempObj = new MyObject("something",1,"something");
MyCollection.Add(tempObj);
...
And I originally had this. It outputs the string, but the object isn't there:
private string SerializeArrayList(ArrayList obj)
{
System.Xml.XmlDocument doc = new XmlDocument();
Type[] extraTypes = new Type[1];
extraTypes[0] = typeof(MyObject);
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ArrayList), extraTypes);
System.IO.MemoryStream stream = new System.IO.MemoryStream();
try
{
serializer.Serialize(stream, obj);
stream.Position = 0;
doc.Load(stream);
return doc.InnerXml;
}
catch { throw; }
finally
{
stream.Close();
stream.Dispose();
}
}
EDIT: Code request
public class MyObject
{
private string eN;
private Boolean bE;
private int min;
private Boolean bot;
private string onE;
public MyObject(string na, Boolean b)
{
...
}
public MyObject()
{
}
public string GetSomething()
{
...
I tested your code and it seems to work ok, as long as you have [Serializable] on your object.
Also if you are trying to Serialize the fields, you will have to make them public properties.
My Test:
ArrayList array = new ArrayList();
Rules tempObj = new Rules { onE = "Value", min = 45, eN = "Value" };
array.Add(tempObj);
string result = SerializeArrayList(array);
private string SerializeArrayList(ArrayList obj)
{
XmlDocument doc = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(typeof(ArrayList), new Type[]{typeof(Rules)});
using (MemoryStream stream = new System.IO.MemoryStream())
{
try
{
serializer.Serialize(stream, obj);
stream.Position = 0;
doc.Load(stream);
return doc.InnerXml;
}
catch (Exception ex)
{
}
}
return string.Empty;
}
Object:
[Serializable]
[XmlType(TypeName = "Rules")]
public class Rules
{
// Make fields propertys so they will be serialized
public string eN { get; set; } //Name
public Boolean bE { get; set; } //Whether blocked entirely
public int min { get; set; } //Minutes they are allowed if blocked
public Boolean bot { get; set; } //Create notification if allowance exceed
public string onE { get; set; } //Nothing or CLOSE Process
public Rules(string na, Boolean b)
{
}
public Rules()
{
}
}
I ran into a similar problem, and there is this great program called SharpSerializer, which is available through Nuget. It will handle your ArrayList quite easily, just type the code:
SharpSerializer mySerializer = new SharpSerializer();
mySerializer.Serialize(ArrayList, "filetosaveto.xml");
Here's the link to the website, its free so don't worry about paying anything:
http://www.sharpserializer.com/en/index.html
Related
I have the following code:
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
saveFileDialog.AddExtension = true;
saveFileDialog.DefaultExt = ".xml";
var resultDialog = saveFileDialog.ShowDialog(this);
if (resultDialog == System.Windows.Forms.DialogResult.OK)
{
string fileName = saveFileDialog.FileName;
SerializeObject(ListaDeBotoes, fileName);
}
}
public void SerializeObject(List<MyButton> serializableObjects, string fileName)
{
if (serializableObjects == null) { return; }
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObjects.GetType());
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, serializableObjects);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileName);
stream.Close();
}
}
catch (Exception ex)
{
//Log exception here
}
}
My objective is to save this list of MyButtons, that is my own class (it is a control too if this matter), in a way that i could re-open it on the future. But this way is not working it stops at: XmlSerializer serializer = new XmlSerializer(serializableObjects.GetType()); and the catch exception is called... Any suggestions?
Try this....
Usings.....
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
Functions....
private void Serialize<T>(T data)
{
// Use a file stream here.
using (TextWriter WriteFileStream = new StreamWriter("test.xml"))
{
// Construct a SoapFormatter and use it
// to serialize the data to the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Serialize EmployeeList to the file stream
SerializerObj.Serialize(WriteFileStream, data);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
}
private T Deserialize<T>() where T : new()
{
//List<Employee> EmployeeList2 = new List<Employee>();
// Create an instance of T
T ReturnListOfT = CreateInstance<T>();
// Create a new file stream for reading the XML file
using (FileStream ReadFileStream = new FileStream("test.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
// Construct a XmlSerializer and use it
// to serialize the data from the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Deserialize the hashtable from the file
ReturnListOfT = (T)SerializerObj.Deserialize(ReadFileStream);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
// return the Deserialized data.
return ReturnListOfT;
}
// function to create instance of T
public static T CreateInstance<T>() where T : new()
{
return (T)Activator.CreateInstance(typeof(T));
}
Usage....
Serialize(dObj); // dObj is List<YourClass>
List<YourClass> deserializedList = Deserialize<List<YourClass>>();
Your object will be written\read to\from a file called test.xml that you can modify to suit....
Hope that helps....
/////////////////////////////////////////////////////////////////////////
An example class to hold your values for each MyButton object might look something like this......
public partial class PropertiesClass
{
public string colorNow { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Black.ToArgb()));
public string backgroundColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Black.ToArgb()));
public string externalLineColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.DarkBlue.ToArgb()));
public string firstColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Goldenrod.ToArgb()));
public string secondColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.DarkGoldenrod.ToArgb()));
public string mouseEnterColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.PaleGoldenrod.ToArgb()));
public string doubleClickColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Gold.ToArgb()));
public bool shouldIChangeTheColor { get; set; } = true;
public bool selectedToMove { get; set; } = true;
public bool selectedToLink { get; set; } = true;
}
Usage...
List<PropertiesClass> PropertiesClasses = new List<PropertiesClass>();
PropertiesClass PropertiesClass = new PropertiesClass();
PropertiesClasses.Add(PropertiesClass);
Serialize(PropertiesClasses);
If thats not a homework or study stuff you better use Json.NET to serialize your classes. Reinvent the well is probably gonna cost you more time.
I have application, which must contain map. To realize this task I create some classes:
1. Map (contains Image and two objects of Location class)
2. GPSPoint (contains two objects of ICoordinate)
3. ImagePoint (contains two int variables)
4. Location (contains GPSPoint and ImagePoint)
And one interface, and two classes, which realize it:
1. ICoordinate
2. GpsCoordinateDeg
3. GpsCoordinateDegMinSec
All of them implements ISerialization interface and have public void GetObjectData(SerializationInfo, StreamingContext) methods.
I want to save my map in the file, and I realize one of the methods of serialization, but it isn't work - I get void xml file:
<?xml version="1.0"?>
<Map xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
I use my class for serialization in this code:
[Serializable]
class Map : ISerializable {
...
public void saveInFile(string filepath) {
Serializer serializer = new Serializer();
serializer.SerializeObject(this, filepath);
}
...
}
This is code of my Serializer:
class Serializer {
public void SerializeObject<T>(T serializableObject, string fileName) {
if (serializableObject == null) { return; }
try {
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream()) {
serializer.Serialize(stream, serializableObject);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileName);
stream.Close();
}
} catch (Exception ex) {
//Log exception here
}
}
public T DeSerializeObject<T>(string fileName) {
if (string.IsNullOrEmpty(fileName)) { return default(T); }
T objectOut = default(T);
try {
string attributeXml = string.Empty;
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(fileName);
string xmlString = xmlDocument.OuterXml;
using (StringReader read = new StringReader(xmlString)) {
Type outType = typeof(T);
XmlSerializer serializer = new XmlSerializer(outType);
using (XmlReader reader = new XmlTextReader(read)) {
objectOut = (T)serializer.Deserialize(reader);
reader.Close();
}
read.Close();
}
} catch (Exception ex) {
//Log exception here
}
return objectOut;
}
}
Where is the problem?
As i dont know the complete implementation of your poco classes i suggest you to look further to your GPSPoint class:
GPSPoint (contains two objects of ICoordinate)
You can not serialize an interface. The problem is that an interface is an opaque type. There is no way for the serializer to know what to write out and more importantly what to create when it needs to serialize things back.
You may look into StackOverflow for "serializing interfaces"-postings. I hope it helps.
Bad idea going for generics with serialization since it heavily relies on object boxing and unboxing.
My way of doing this does not rely on implementing ISerializable, rather on the careful use of attributes.
Decorate each class below with [Serializable()], [XmlType(AnonymousType=true)], [XmlRoot(Namespace="", IsNullable=false)]. The enum stands for coordinate types. Derive your existing classes from these ones. Mark properties you do not want serialized with [XmlIgnore] in your derived classes. Make Coordinate below implement your ICoordinate.
public partial class Location {
[XmlElement]
public GPSPoint GPSPoint { get; set; }
[XmlElement]
public ImagePoint ImagePoint { get; set; }
}
public partial class GPSPoint {
[XmlElement(ElementName = "Coordinate", Order = 0)]
public Coordinate Coordinate1 {get; set; }
[XmlElement(Order=1, ElementName="Coordinate")]
public Coordinate Coordinate2 {get;set;}
}
public partial class Coordinate {
[XmlAttribute()]
public ICoordinateType type {get;set;}
}
[Serializable]
public enum ICoordinateType {
/// <remarks/>
GpsCoordinateDegMinSec,
/// <remarks/>
GpsCoordinateDeg,
}
public partial class Map {
[XmlElement(Order=0, IsNullable=true)]
public object Image { get; set; }
/// <remarks/>
[XmlElement(ElementName="Location", Order = 1)]
public Location Location1 {get; set; }
/// <remarks/>
[XmlElement(ElementName = "Location", Order = 2)]
public Location Location2 {get; set; }
}
This is tested and running:
var tc1 = new xyz.Coordinate () {type = xyz.ICoordinateType.GpsCoordinateDeg};
var tc2 = new xyz.Coordinate () {type = xyz.ICoordinateType.GpsCoordinateDegMinSec};
var l1 = new xyz.Location() {
GPSPoint = new xyz.GPSPoint() { Coordinate1 = tc1, Coordinate2 = tc2 },
ImagePoint = new xyz.ImagePoint() { x = 0, y = 0 } };
xyz.Map m = new xyz.Map() {
Image = null,
Location1 = l1,
Location2 = new xyz.Location() {
GPSPoint = new xyz.GPSPoint() {
Coordinate1 = tc1, Coordinate2 = tc2 },
ImagePoint = new xyz.ImagePoint() { x = 1, y = 2 }
} };
XmlSerializer xs = new XmlSerializer(typeof(Map));
using (var fs = File.Create("map.xml") ) { xs.Serialize(fs, m); }
I've got an object which has a circular dependency
public class Levels
{
public UserDescription user { get; set; }
public List<Levels> friends {get; set;}
public Levels(UserDescription user, List<Levels> friends)
{
this.user = user;
this.friends = friends;
}
public Levels() { }
}
I need to serialize it to xml, so I do the following:
public string SerializeObject(object obj)
{
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
serializer.Serialize(ms, obj);
ms.Position = 0;
xmlDoc.Load(ms);
return xmlDoc.InnerXml;
}
}
This code throws an exception System.InvalidOperationException onserializer = new System.Xml.Serialization.XmlSerializer. How can I solve this?
The problem was that class UserDescription didn't have an empty constructor.
Given
public class Something
{
[JsonProperty(PropertyName = "Ver")]
public string ver { get; set; }
[JsonProperty(PropertyName = "SomethingElse")]
public object somethingElse { get; set; } // will blow up
// public SomethingElse somethingElse { get; set; } // will not
}
public class SomethingElse
{
[JsonProperty(PropertyName = "uuid")]
public Guid uuid { get; set; }
}
Attempting to serialize then deserialize Something will throw Unable cast object of type Guid to Byte[] exception if the member somethingelse of something is an object rather than the type itself.
Sorry for the lack of details. Above was a simplified class that you can serialize but cannot deserialize the object. Below matches are situation more closely, only difference is the dictionary we need is , that will fail as well in the exact same manner. The example works with JSOn, not BSON. The serialization appears valid, just the deserialization throws an exception in the JSonWriter Unable to cast object of type 'System.Guid' to type 'System.Byte[]',line 552
case JsonToken.Bytes:
WriteValue((byte[])reader.Value);<-- is trying to case a Guid to byte array
break;
static void Main(string[] args)
{
const string path = #"C:\zzz_bson.dat";
WriteBson(path);
ReadBson(path);
}
private static void ReadBson(string path)
{
var jsonSerializer = new JsonSerializer();
var file = File.OpenRead(path);
var binaryReader = new BinaryReader(file);
var bsonReader = new BsonReader(binaryReader);
var something = jsonSerializer.Deserialize(bsonReader);
file.Close();
}
private static void WriteBson(string path)
{
//var something = new Dictionary<string, Guid> { { "uuid", new Guid("8afbc8b8-5449-4c70-abd4-3e07046d0f61") } }; //fails
var something = new Dictionary<string, string> { { "uuid", new Guid("8afbc8b8-5449-4c70-abd4-3e07046d0f61").ToString() } }; // works
var jsonSerializer = new JsonSerializer();
var file = File.OpenWrite(path);
var binaryWriter = new BinaryWriter(file);
var bsonWriter = new BsonWriter(binaryWriter);
jsonSerializer.Serialize(bsonWriter, something);
file.Close();
}
In the example code below, I get this error:
Element
TestSerializeDictionary123.Customer.CustomProperties
vom Typ
System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089],[System.Object,
mscorlib, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089]] can
not be serialized because it
implements IDictionary.
When I take out the Dictionary property, it works fine.
How can I serialize this Customer object with the dictionary property? Or what replacement type for Dictionary can I use that would be serializable?
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Text;
namespace TestSerializeDictionary123
{
public class Program
{
static void Main(string[] args)
{
List<Customer> customers = Customer.GetCustomers();
Console.WriteLine("--- Serializing ------------------");
foreach (var customer in customers)
{
Console.WriteLine("Serializing " + customer.GetFullName() + "...");
string xml = XmlHelpers.SerializeObject<Customer>(customer);
Console.WriteLine(xml);
Console.WriteLine("Deserializing ...");
Customer customer2 = XmlHelpers.DeserializeObject<Customer>(xml);
Console.WriteLine(customer2.GetFullName());
Console.WriteLine("---");
}
Console.ReadLine();
}
}
public static class StringHelpers
{
public static String UTF8ByteArrayToString(Byte[] characters)
{
UTF8Encoding encoding = new UTF8Encoding();
String constructedString = encoding.GetString(characters);
return (constructedString);
}
public static Byte[] StringToUTF8ByteArray(String pXmlString)
{
UTF8Encoding encoding = new UTF8Encoding();
Byte[] byteArray = encoding.GetBytes(pXmlString);
return byteArray;
}
}
public static class XmlHelpers
{
public static string SerializeObject<T>(object o)
{
MemoryStream ms = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(T));
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
xs.Serialize(xtw, o);
ms = (MemoryStream)xtw.BaseStream;
return StringHelpers.UTF8ByteArrayToString(ms.ToArray());
}
public static T DeserializeObject<T>(string xml)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml));
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
return (T)xs.Deserialize(ms);
}
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Street { get; set; }
public string Location { get; set; }
public string ZipCode { get; set; }
public Dictionary<string,object> CustomProperties { get; set; }
private int internalValue = 23;
public static List<Customer> GetCustomers()
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" });
customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" });
customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" });
customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" });
customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" });
return customers;
}
public string GetFullName()
{
return FirstName + " " + LastName + "(" + internalValue + ")";
}
}
}
In our application we ended up using:
DataContractSerializer xs = new DataContractSerializer(typeof (T));
instead of:
XmlSerializer xs = new XmlSerializer(typeof (T));
which solved the problem as DatacontractSerializer supports Dictionary.
Another solution is ths XML Serializable Generic Dictionary workaround also works in the above example, and there is a long discussion at that link from people using it, might be useful for people working with this issue.
Here's a generic dictionary class that knows how to serialize itself:
public class XmlDictionary<T, V> : Dictionary<T, V>, IXmlSerializable {
[XmlType("Entry")]
public struct Entry {
public Entry(T key, V value) : this() { Key = key; Value = value; }
[XmlElement("Key")]
public T Key { get; set; }
[XmlElement("Value")]
public V Value { get; set; }
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() {
return null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) {
this.Clear();
var serializer = new XmlSerializer(typeof(List<Entry>));
reader.Read(); // Why is this necessary?
var list = (List<Entry>)serializer.Deserialize(reader);
foreach (var entry in list) this.Add(entry.Key, entry.Value);
reader.ReadEndElement();
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) {
var list = new List<Entry>(this.Count);
foreach (var entry in this) list.Add(new Entry(entry.Key, entry.Value));
XmlSerializer serializer = new XmlSerializer(list.GetType());
serializer.Serialize(writer, list);
}
}
You can't (short of doing it all yourself, which is horrible); the xml serializer isn't going to have a clue what to do with object, as it doesn't include type metadata in the wire format. One (hacky) option would be to stream these all as strings for the purposes of serialization, but then you have a lot of extra parsing (etc) code to write.
You can use Binary serialization instead. (Just make sure all your classes are marked as [Serializable]. Of course, it won't be in XML format, but you didn't list that as a requirement :)
I've just found this blog post by Rakesh Rajan which describes one possible solution:
Override XmlSerialization by making the type implement the System.Xml.Serialization.IXmlSerializable class. Define how you want the object to be serialized in XML in the WriteXml method, and define how you could recreate the object from an xml string in the ReadXml method.
But this wouldn't work as your Dictionary contains an object rather than a specific type.
What about to mark Customer class as DataContract and its properties as DataMembers. DataContract serializer will do the serialization for you.
Try Serializating through BinaryFormatter
private void Deserialize()
{
try
{
var f_fileStream = File.OpenRead(#"dictionarySerialized.xml");
var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
myDictionary = (Dictionary<string, myClass>)f_binaryFormatter.Deserialize(f_fileStream);
f_fileStream.Close();
}
catch (Exception ex)
{
;
}
}
private void Serialize()
{
try
{
var f_fileStream = new FileStream(#"dictionarySerialized.xml", FileMode.Create, FileAccess.Write);
var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
f_binaryFormatter.Serialize(f_fileStream, myDictionary);
f_fileStream.Close();
}
catch (Exception ex)
{
;
}
}