This question already has answers here:
Using XmlSerializer to serialize derived classes
(3 answers)
Closed 4 years ago.
I tried following the Microsoft website documentation for addressing the above question. However, I'm not able to find the answer. So I tried writing the code, but my object is not getting serialized when I added more derived classes.
Here goes the code:
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
public class Orchestra
{
// public Instrument[] Instruments;
public List<Instrument> Instruments;
public int i;
public float f;
public string s1;
public string s2;
public B bc;
}
public class B
{
public double dd;
}
public class Instrument
{
public string Name;
}
public class Brass : Instrument
{
public bool IsValved;
}
public class Percussion : Instrument
{
public string name;
}
public class Run
{
public static void Main()
{
Run test = new Run();
test.SerializeObject("Override.xml");
test.DeserializeObject("Override.xml");
}
public void SerializeObject(string filename)
{
/* Each overridden field, property, or type requires
an XmlAttributes object. */
XmlAttributes attrs = new XmlAttributes();
/* Create an XmlElementAttribute to override the
field that returns Instrument objects. The overridden field
returns Brass objects instead. */
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
attrs.XmlElements.Add(attr);
// attrs.XmlArrayItems.Add(attr);
attr.ElementName = "Percussion";
attr.Type = typeof(Percussion);
// Add the element to the collection of elements.
attrs.XmlElements.Add(attr);
// Create the XmlAttributeOverrides object.
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
/* Add the type of the class that contains the overridden
member and the XmlAttributes to override it with to the
XmlAttributeOverrides object. */
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
// Writing the file requires a TextWriter.
TextWriter writer = new StreamWriter(filename);
// Create the object that will be serialized.
Orchestra band = new Orchestra();
// Create an object of the derived type.
//Brass i = new Brass();
//i.Name = "Trumpet";
//i.IsValved = true;
//Instrument[] myInstruments = { i };
//band.Instruments = myInstruments;
List<Instrument> myInstruments = new List<Instrument>();
myInstruments.Add(new Brass() { Name = "Trumpet", IsValved = true });
myInstruments.Add(new Percussion() { Name = "Percussion", name = "Mridangam" });
band.Instruments = myInstruments;
band.i = 128;
band.f = 5.678f;
band.s1 = "Hi!";
band.s2 = "GOOD!!!";
B b = new B();
b.dd = 2.35674848;
band.bc = b;
// Serialize the object.
s.Serialize(writer, band);
writer.Close();
}
public void DeserializeObject(string filename)
{
XmlAttributeOverrides attrOverrides =
new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// Create an XmlElementAttribute to override the Instrument.
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
// Add the element to the collection of elements.
attrs.XmlElements.Add(attr);
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestra band = (Orchestra)s.Deserialize(fs);
Console.WriteLine(band.i);
Console.WriteLine(band.f);
Console.WriteLine(band.s1);
Console.WriteLine(band.s2);
Console.WriteLine(band.bc.dd);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
//Brass b;
//Percussion p;
Brass b;
// Percussion p;
//b = (Brass)i;
// int ii = 0;
foreach (Instrument i in band.Instruments)
//foreach(Instrument i in band.List<Instrument>)
{
// int i = 0;
// ii++;
// if (ii == 1)
// {
b = (Brass)i;
Console.WriteLine(
b.Name + "\n" +
b.IsValved);
// }
/*if (ii == 2)
{
p = (Percussion)i;
Console.WriteLine(
p.Name + "\n" +
p.name);
}*/
}
}
}
I even tried using XmlArrayItem. Could anyone guide how to go about this?
You have to add a new class Instruments to your code. See code below :
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml;
public class Orchestras
{
public List<Orchestra> orchestras = new List<Orchestra>();
}
public class Orchestra
{
[XmlElement]
public List<Instrument> Instruments { get; set; }
public int i;
public float f;
public string s1;
public string s2;
public B bc;
}
public class B
{
public double dd;
}
[XmlInclude(typeof(Brass))]
[XmlInclude(typeof(Percussion))]
public class Instrument
{
public string Name;
}
public class Brass : Instrument
{
public bool IsValved;
}
public class Percussion : Instrument
{
public string name;
}
public class Run
{
const string FILENAME = #"c:\temp\test.xml";
public static void Main()
{
Run test = new Run();
test.SerializeObject(FILENAME);
test.DeserializeObject(FILENAME);
}
public void SerializeObject(string filename)
{
Orchestras orchastras = new Orchestras();
Orchestra orchestra1 = new Orchestra();
orchastras.orchestras.Add(orchestra1);
List<Instrument> instruments = new List<Instrument>() {
new Instrument() { Name = "Brass"},
new Instrument() { Name = "Percussion"}
};
orchestra1.Instruments = instruments;
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s = new XmlSerializer(typeof(Orchestras));
// Writing the file requires a TextWriter.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(filename,settings);
// Create the object that will be serialized.
Orchestra band = new Orchestra();
orchastras.orchestras.Add(band);
// Create an object of the derived type.
//Brass i = new Brass();
//i.Name = "Trumpet";
//i.IsValved = true;
//Instrument[] myInstruments = { i };
//band.Instruments = myInstruments;
List<Instrument> myInstruments = new List<Instrument>();
myInstruments.Add(new Brass() { Name = "Trumpet", IsValved = true });
myInstruments.Add(new Percussion() { Name = "Percussion", name = "Mridangam" });
band.Instruments = myInstruments;
band.i = 128;
band.f = 5.678f;
band.s1 = "Hi!";
band.s2 = "GOOD!!!";
B b = new B();
b.dd = 2.35674848;
band.bc = b;
// Serialize the object.
s.Serialize(writer, orchastras);
writer.Close();
}
public void DeserializeObject(string filename)
{
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestras));
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestras band = (Orchestras)s.Deserialize(fs);
Console.WriteLine(band.orchestras[1].i);
Console.WriteLine(band.orchestras[1].f);
Console.WriteLine(band.orchestras[1].s1);
Console.WriteLine(band.orchestras[1].s2);
Console.WriteLine(band.orchestras[1].bc.dd);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
//Brass b;
//Percussion p;
Instrument b;
// Percussion p;
//b = (Brass)i;
// int ii = 0;
foreach (Instrument i in band.orchestras[1].Instruments)
//foreach(Instrument i in band.List<Instrument>)
{
// int i = 0;
// ii++;
// if (ii == 1)
// {
b = i;
Console.WriteLine(
b.Name + "\n");
// }
/*if (ii == 2)
{
p = (Percussion)i;
Console.WriteLine(
p.Name + "\n" +
p.name);
}*/
}
}
}
Related
So I want to create constructor for my class EmployeeNodeClass that takes In EmployeeNodeClass object and copies it using a deepclone funtion:
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
to the new object.
At first i thought that it is as simple as
public EmployeeNodeClass(EmployeeNodeClass EMPND)
{
this = DeepClone(EMPND);
}
but then I got the error that this is readonly.
so how can I do it?
It can be done using NewtonSoft JsonConvert.PopulateObject:
Example:
class Entity
{
public List<int> List { get; set; }
public Entity(List<int> list)
{
List = list;
}
public Entity(Entity original)
{
string originalJson = JsonConvert.SerializeObject(original);
JsonConvert.PopulateObject(originalJson, this);
}
}
And using it:
static void Main(string[] args)
{
var entity1 = new Entity(new List<int> { 1, 2, 3 });
var entity2 = new Entity(entity1);
entity1.List[0] = 5;
Console.WriteLine(entity2.List[0]);
}
Note: since this uses NewtonSoft Json, it will only clone public, writable properties. So internal state in private fields (that are not associated with such properties) will be lost.
I'm trying to deserialize a bunch of data that was serialized by an old version of the code. When the data was serialized the classes had a different structure from the current class structure. To keep this data working in my new code, I hade to add the old classes structure to the code just for import this serialized data. I'm calling this classes as 'class'_oldVersions. To deserialize, I'm using this code:
className_oldVersions temp_className = new className_oldVersions();
XmlSerializer testSerializer = new XmlSerializer(typeof(className_oldVersions),
new XmlRootAttribute { ElementName = "className" });
temp_className = (ObservedData_OldVersions)testSerializer.Deserialize(ms_MemoryStream);
This code works fine, and I can deserialize the data using a diffent class name from the original. My problem is when I try to use this same procedure to deserialize an observable collection.
I created a code that reproduce my problem. In this code I serialize an observable collection of class OptimizationVariables and I would like to deserialize to an observable collection of class OptimizationVariablies_NewClass that has similar structure from the original one.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
public class OptimizationVariables
{
public string VariableName { get; set; }
}
public class OptimizationVariables_NewClass
{
public string VariableName { get; set; }
}
public class ModelsCollection
{
private ModelsCollection()
{
}
private ObservableCollection<OptimizationVariables> m_optimizationVariables =
new ObservableCollection<OptimizationVariables>();
public ObservableCollection<OptimizationVariables> OptimizationVariables
{
get { return m_optimizationVariables; }
set { m_optimizationVariables = value; }
}
private ObservableCollection<OptimizationVariables_NewClass> m_optimizationVariables_NewClass =
new ObservableCollection<OptimizationVariables_NewClass>();
public ObservableCollection<OptimizationVariables_NewClass> OptimizationVariables_NewClass
{
get { return m_optimizationVariables_NewClass; }
set { m_optimizationVariables_NewClass = value; }
}
}
class Program
{
static void Main(string[] args)
{
//Here I serialize an ObservableCollection of 2 OptimizationVariables instances
Serialize();
//Here I deserialize for the same class and works fine
Deserialize();
//Here I try to deserialize to a new class with same structure, but different name. I a have an error.
Deserialize2NewClass();
}
static void Serialize()
{
MemoryStream ms;
ObservableCollection<OptimizationVariables> OptimizationVariables2Serialize = new ObservableCollection<OptimizationVariables>();
OptimizationVariables opt_var1 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 1";
OptimizationVariables2Serialize.Add(opt_var1);
OptimizationVariables opt_var2 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 2";
OptimizationVariables2Serialize.Add(opt_var1);
ms = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
serializer.Serialize(ms, OptimizationVariables2Serialize);
TextWriter sw = new StreamWriter("XML_File_x64.bin");
sw.WriteLine(Convert.ToBase64String(ms.ToArray()));
sw.Close();
}
static void Deserialize()
{
byte[] memoryData;
MemoryStream ms;
TextReader sw = new StreamReader("XML_File_x64.bin");
memoryData = Convert.FromBase64String(sw.ReadLine());
ms = new MemoryStream(memoryData);
ObservableCollection<OptimizationVariables> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables>)deserializer.Deserialize(ms);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
static void Deserialize2NewClass()
{
byte[] memoryData;
MemoryStream ms;
TextReader sw = new StreamReader("XML_File_x64.bin");
memoryData = Convert.FromBase64String(sw.ReadLine());
ms = new MemoryStream(memoryData);
ObservableCollection<OptimizationVariables_NewClass> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables_NewClass>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables_NewClass>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables_NewClass>)deserializer.Deserialize(ms);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
}
The problem in your code is that the class OptimizationVariables name is saved in the xml data when serializing. but for deserialization it expects a OptimizationVariables_NewClass name which is not within the xml file.
consider the fact that not only the variable names, but also the class names will be used when serializing a class or struct...
So, just changed your code to make it save the data in readable xml file, then replacing "OptimizationVariables" with "OptimizationVariables_NewClass" solved the error:
using System;
using System.Linq;
using System.IO;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
public class OptimizationVariables
{
public string VariableName { get; set; }
}
public class OptimizationVariables_NewClass
{
public string VariableName { get; set; }
}
public class ModelsCollection
{
private ModelsCollection()
{
}
private ObservableCollection<OptimizationVariables> m_optimizationVariables =
new ObservableCollection<OptimizationVariables>();
public ObservableCollection<OptimizationVariables> OptimizationVariables
{
get { return m_optimizationVariables; }
set { m_optimizationVariables = value; }
}
private ObservableCollection<OptimizationVariables_NewClass> m_optimizationVariables_NewClass =
new ObservableCollection<OptimizationVariables_NewClass>();
public ObservableCollection<OptimizationVariables_NewClass> OptimizationVariables_NewClass
{
get { return m_optimizationVariables_NewClass; }
set { m_optimizationVariables_NewClass = value; }
}
}
class Program
{
static void Main(string[] args)
{
Serialize();
Deserialize();
Deserialize2NewClass();
}
static void Serialize()
{
ObservableCollection<OptimizationVariables> OptimizationVariables2Serialize = new ObservableCollection<OptimizationVariables>();
OptimizationVariables opt_var1 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 1";
OptimizationVariables2Serialize.Add(opt_var1);
OptimizationVariables opt_var2 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 2";
OptimizationVariables2Serialize.Add(opt_var1);
TextWriter writer = new StreamWriter("XML_File.xml");
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
serializer.Serialize(writer, OptimizationVariables2Serialize);
writer.Close();
}
static void Deserialize()
{
TextReader sw = new StreamReader("XML_File.xml");
ObservableCollection<OptimizationVariables> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables>)deserializer.Deserialize(sw);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
static void Deserialize2NewClass()
{
TextReader sw = new StreamReader("XML_File.xml");
var str = sw.ReadToEnd();
sw.Close();
str = str.Replace("OptimizationVariables", "OptimizationVariables_NewClass");
var stream = new StringReader(str);
ObservableCollection<OptimizationVariables_NewClass> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables_NewClass>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables_NewClass>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables_NewClass>)deserializer.Deserialize(stream);
Console.Write(OptimizationVariablesDeserialized.Count());
}
}
now it works fine!
I got some issues with the XmlSerializer in .NET.
Here I have a small example I built up just right now. (also available # gist https://gist.github.com/2d84be9041a3f9c06237)
using System.IO;
using System.Xml.Serialization;
namespace XmlSerializingSample
{
internal class Program
{
private static void Main(string[] args)
{
var specialType = new SpecialType()
{
Id = 1,
Name = "test"
};
var serializer = new XmlSerializer(typeof (SpecialType));
var des = new XmlSerializer(typeof (BaseType));
using (var memeStream = new MemoryStream())
{
serializer.Serialize(memeStream, specialType);
memeStream.Flush();
memeStream.Seek(0, SeekOrigin.Begin);
var instance = des.Deserialize(memeStream); // Here it throws the exception
}
}
}
[XmlInclude(typeof(SpecialType))]
[XmlType("baseType")]
public class BaseType
{
public long Id { get; set; }
}
[XmlRoot("special")]
public class SpecialType : BaseType
{
public string Name { get; set; }
}
}
In line 24 of the code I get an InvalidOperationException stating "{"<special xmlns=''> wurde nicht erwartet."}" [yes, it's german]
All Posts I found stated, after adding XmlIncludeAttribute on the base type being deserialized, this should work. Did I forget sth.?
Regards,
MacX
The problem is that your Serializer is serializing the SpecialType with a root element as so:
<special ...>
<Id>...
But then you try to Deserialize it using var des = new XmlSerializer(typeof (BaseType)); it knows about both types but it doesn't know how to handle the root element in the xml.
If you want this to work, you need to also set the root element of the base type to serialize as special. In other words, you would need to do this:
[XmlInclude(typeof(SpecialType))]
[XmlType("baseType")]
[XmlRoot("special")]
public class BaseType
{
public long Id { get; set; }
}
That way, the deserializer knows how to handle special as the root element.
I don't think there are other simple alternatives to make this work out of the box.
Update
This is another alternative using the XmlAttributeOverrides class.
LinqPad code:
void Main()
{
var specialType = new SpecialType()
{
Id = 1,
Name = "test"
};
var serializer = new XmlSerializer(typeof (SpecialType));
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// Create an XmlRootAttribute to override.
XmlRootAttribute attr = new XmlRootAttribute();
attr.ElementName = "special";
// Add the XmlRootAttribute to the collection of objects.
attrs.XmlRoot=attr;
attrOverrides.Add(typeof(BaseType), attrs);
var des = new XmlSerializer(typeof (BaseType), attrOverrides);
using (var memeStream= new MemoryStream())
{
serializer.Serialize(memeStream, specialType);
memeStream.Flush();
memeStream.Seek(0, SeekOrigin.Begin);
var instance = des.Deserialize(memeStream);
}
}
[XmlInclude(typeof(SpecialType))]
[XmlType("baseType")]
public class BaseType
{
public long Id { get; set; }
}
[XmlRoot("special")]
public class SpecialType : BaseType
{
public string Name { get; set; }
}
I'm having a problem with the c# XML serialization system it's throws an Ambigus exception,
There was an error generating the XML document.
Now i have a Class that contains refferences to other classes and arrays of the other classes
E.G
namespace P2PFileLayout
{
public class p2pfile
{
public FileList FileList;
public StatusServer StatusServer;
public String Hash;
}
}
namespace P2PFileLayout.parts
{
public class StatusServer
{
public Auth Auth;
public Servers Servers;
}
public class Servers
{
public Server[] Server;
}
public class Server
{
public bool AuthRequired = false;
public string Address;
}
public class Files
{
public File[] File;
}
public class File
{
public string FileName = "";
public int BlockSize = 0;
public int BlockCount = 0;
}
public class Directory
{
public string Name;
public Files Files;
public Directory[] Dir;
}
public class Auth
{
public AuthServer[] AuthServer;
}
public class FileList
{
public Files Files;
public Directory[] Directory;
}
}
My Example data
// create the test file
testFile = new p2pfile();
// create a fake fileList
testFile.FileList = new P2PFileLayout.parts.FileList();
testFile.FileList.Directory = new P2PFileLayout.parts.Directory[1];
testFile.FileList.Directory[0] = new P2PFileLayout.parts.Directory();
testFile.FileList.Directory[0].Name = "testFolder";
testFile.FileList.Directory[0].Files = new P2PFileLayout.parts.Files();
testFile.FileList.Directory[0].Files.File = new P2PFileLayout.parts.File[2];
testFile.FileList.Directory[0].Files.File[0] = new P2PFileLayout.parts.File();
testFile.FileList.Directory[0].Files.File[0].FileName = "test.txt";
testFile.FileList.Directory[0].Files.File[0].BlockSize = 64;
testFile.FileList.Directory[0].Files.File[0].BlockCount = 1;
testFile.FileList.Directory[0].Files.File[1] = new P2PFileLayout.parts.File();
testFile.FileList.Directory[0].Files.File[1].FileName = "test2.txt";
testFile.FileList.Directory[0].Files.File[1].BlockSize = 64;
testFile.FileList.Directory[0].Files.File[1].BlockCount = 1;
// create a fake status server
testFile.StatusServer = new P2PFileLayout.parts.StatusServer();
testFile.StatusServer.Servers = new P2PFileLayout.parts.Servers();
testFile.StatusServer.Servers.Server = new P2PFileLayout.parts.Server[1];
testFile.StatusServer.Servers.Server[0] = new P2PFileLayout.parts.Server();
testFile.StatusServer.Servers.Server[0].Address = "http://localhost:8088/list.php";
// create a file hash (real)
HashGenerator.P2PHash hashGen = new HashGenerator.P2PHash();
testFile.Hash = hashGen.getHash();
treeView1.Nodes.Add(new TreeNode("Loading..."));
Classes.CreateTreeView ctv = new Classes.CreateTreeView();
ctv.BuildTreeView(testFile.FileList, treeView1);
treeView1.AfterCheck += new TreeViewEventHandler(treeView1_AfterCheck);
Now that is not as complicated as mine in terms of dept as my i loop objects so dir has support for more dirs but thats just an example
Then i'm serializing to a string var as i want to do a little more than just serialize it but here is my serialization
private string ToXml(object Obj, System.Type ObjType)
{
// instansiate the xml serializer object
XmlSerializer ser = new XmlSerializer(ObjType);
// create a memory stream for XMLTextWriter to use
MemoryStream memStream = new MemoryStream();
// create an XML writer using our memory stream
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.UTF8);
// write the object though the XML serializer method using the W3C namespaces
ser.Serialize(xmlWriter, Obj);
// close the XMLWriter
xmlWriter.Close();
// close the memoryStream
memStream.Close();
// get the string from the memory Stream
string xml = Encoding.UTF8.GetString(memStream.GetBuffer());
// remove the stuff before the xml code we care about
xml = xml.Substring(xml.IndexOf(Convert.ToChar(60)));
// clear any thing at the end of the elements we care about
xml = xml.Substring(0, (xml.LastIndexOf(Convert.ToChar(62)) + 1));
// return the XML string
return xml;
}
Can any one see why this is not working or any clues as to why it would not work normally
Why are you doing it manually?
What about this approach?
http://support.microsoft.com/kb/815813
Test test = new Test() { Test1 = "1", Test2 = "3" };
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(test.GetType());
MemoryStream ms = new MemoryStream();
x.Serialize(ms, test);
ms.Position = 0;
StreamReader sr = new StreamReader(ms);
string xml = sr.ReadToEnd();
As for the ambigous message, take a look into the inner exceptions. XML serialization errors use innerexception a lot, and you usually have to look to all levels of InnerExceptions to know what is really happening.
While using this code to serialize an object:
public object Clone()
{
var serializer = new DataContractSerializer(GetType());
using (var ms = new System.IO.MemoryStream())
{
serializer.WriteObject(ms, this);
ms.Position = 0;
return serializer.ReadObject(ms);
}
}
I have noticed that it doesn't copy the relationships.
Is there any way to make this happen?
Simply use the constructor overload that accepts preserveObjectReferences, and set it to true:
using System;
using System.Runtime.Serialization;
static class Program
{
public static T Clone<T>(T obj) where T : class
{
var serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, true, null);
using (var ms = new System.IO.MemoryStream())
{
serializer.WriteObject(ms, obj);
ms.Position = 0;
return (T)serializer.ReadObject(ms);
}
}
static void Main()
{
Foo foo = new Foo();
Bar bar = new Bar();
foo.Bar = bar;
bar.Foo = foo; // nice cyclic graph
Foo clone = Clone(foo);
Console.WriteLine(foo != clone); //true - new object
Console.WriteLine(clone.Bar.Foo == clone); // true; copied graph
}
}
[DataContract]
class Foo
{
[DataMember]
public Bar Bar { get; set; }
}
[DataContract]
class Bar
{
[DataMember]
public Foo Foo { get; set; }
}
Either annotate your classes with [DataContract] or add your child types in the constructor of DatacontractSerializer.
var knownTypes = new List<Type> {typeof(Class1), typeof(Class2), ..etc..};
var serializer = new DataContractSerializer(GetType(), knownTypes);
To perform a deep clone you might consider using a binary serializer:
public static object CloneObject(object obj)
{
using (var memStream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter(
null,
new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, obj);
memStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(memStream);
}
}
You need a binary serializer to preserve objects identity during the serialization/deserialization step.