XML serialize doesn't work

T

Tony Johansson

Hello!

I try to understand why I can't XML serialize when I use inheriatance with
abstract class.
In this example I have a Person class which is abstract and the base class.
I have then a derived class Student as you can see here.
public abstract class Person
{
private string name;
public Person() //Default c_tor
{}

public Person(string name)
{
this.name = name;
}

public string Name
{
get { return name; }
set { name = value; }
}
}

public class Student : Person
{
private string collage;
public Student() //Default C-tor
{}

public Student(string name, string collage) : base(name)
{
this.collage = collage;
}

public string Collage
{
get { return collage; }
set { collage = value; }
}
}

I have then an event hander called MenuFileExportToXML that is listed just
below. The code maked 1 and 2 below give an Exception in the generic method
XMLSerialize that is listed below the exception says.It was not possible to
generate the XML-documentet. As you can see in the code marked 1 and 2 I
create the generic List as List<Person>
In the code marked 3 below I it works fine because here I create the generic
List as List<Student>.

So my question is how should I write to be able to serialize the object
Person ?
This seems very strange because writing as I have done in the code marked as
1 and 2 is very common but the
XmlSerializer doesn't like it for some reason.

private void MenuFileExportToXML_Click(object sender, EventArgs e)
{
1 List<Person> myListNotWork1 = new List<Person>();
1 Person p1 = new Student("olle", "sundsta");
1 myListNotWork1.Add(p1);
1 XMLSerialization.XMLSerialize<List<Person>>(XMLFile, myListNotWork1);


2 List<Person> myListNotWork2= new List<Person>();
2 Student s1 = new Student("olle", "sundsta");
2 myListNotWork2.Add(s1);
2 XMLSerialization.XMLSerialize<List<Person>>(XMLFile, myListNotWork2);

3 List<Student> myListWork = new List<Student>();
3 Student s1 = new Student("olle", "sundsta");
3 myListWork.Add(s1);
3 XMLSerialization.XMLSerialize<List<Student>>(XMLFile, myListWork);
}

public class XMLSerialization
{
public static void XMLSerialize<T>(string filePath, T obj)
{
try
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T));
XmlSer.Serialize(fs, obj);
}
}
catch(Exception ex)
{
string slask = ex.Message;

}
}
}

//Tony
 
A

Arne Vajhøj

I try to understand why I can't XML serialize when I use inheriatance with
abstract class.
In this example I have a Person class which is abstract and the base class.
I have then a derived class Student as you can see here.
public abstract class Person
{
private string name;
public Person() //Default c_tor
{}

public Person(string name)
{
this.name = name;
}

public string Name
{
get { return name; }
set { name = value; }
}
}

public class Student : Person
{
private string collage;
public Student() //Default C-tor
{}

public Student(string name, string collage) : base(name)
{
this.collage = collage;
}

public string Collage
{
get { return collage; }
set { collage = value; }
}
}

I have then an event hander called MenuFileExportToXML that is listed just
below. The code maked 1 and 2 below give an Exception in the generic method
XMLSerialize that is listed below the exception says.It was not possible to
generate the XML-documentet. As you can see in the code marked 1 and 2 I
create the generic List as List<Person>
In the code marked 3 below I it works fine because here I create the generic
List as List<Student>.

So my question is how should I write to be able to serialize the object
Person ?
This seems very strange because writing as I have done in the code marked as
1 and 2 is very common but the
XmlSerializer doesn't like it for some reason.

private void MenuFileExportToXML_Click(object sender, EventArgs e)
{
1 List<Person> myListNotWork1 = new List<Person>();
1 Person p1 = new Student("olle", "sundsta");
1 myListNotWork1.Add(p1);
1 XMLSerialization.XMLSerialize<List<Person>>(XMLFile, myListNotWork1);


2 List<Person> myListNotWork2= new List<Person>();
2 Student s1 = new Student("olle", "sundsta");
2 myListNotWork2.Add(s1);
2 XMLSerialization.XMLSerialize<List<Person>>(XMLFile, myListNotWork2);

3 List<Student> myListWork = new List<Student>();
3 Student s1 = new Student("olle", "sundsta");
3 myListWork.Add(s1);
3 XMLSerialization.XMLSerialize<List<Student>>(XMLFile, myListWork);
}

public class XMLSerialization
{
public static void XMLSerialize<T>(string filePath, T obj)
{
try
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T));
XmlSer.Serialize(fs, obj);
}
}
catch(Exception ex)
{
string slask = ex.Message;

}
}
}

There are two fundamental problems:
1) you eat exceptions so you don't know what is happening
2) as we discussed last month, then you need to specify additional types
to be used in XML serialization

See code below.

Arne

========

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace E
{
public abstract class Person
{
private string name;
public Person() : this("") // to avoid null
{
}
public Person(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
set { name = value; }
}
}
public class Student : Person
{
private string college;
public Student() : this("", "") // to avoid null
{
}
public Student(string name, string college) : base(name)
{
this.college = college;
}
public string College
{
get { return college; }
set { college = value; }
}
}
public class XMLSerialization
{
public static void XMLSerialize<T>(string filePath, T obj,
Type[] additional) // addd the additional types needed
{
try
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T),
additional);
XmlSer.Serialize(fs, obj);
}
}
catch(Exception ex)
{
Console.WriteLine(ex); // **** NEVER EVER JUST EAT THE
EXCEPTION !!!! ****

}
}
}
public class Program
{
public static void Main(string[] args)
{
List<Person> myListNotWork1 = new List<Person>();
Person p1 = new Student("olle", "sundsta");
myListNotWork1.Add(p1);
XMLSerialization.XMLSerialize(@"C:\z1.xml", myListNotWork1,
new Type[] { typeof(Student) }); // infer T and add Student as
additional type
List<Person> myListNotWork2= new List<Person>();
Student s1 = new Student("olle", "sundsta");
myListNotWork2.Add(s1);
XMLSerialization.XMLSerialize(@"C:\z2.xml", myListNotWork2,
new Type[] { typeof(Student) }); // infer T and add Student as
additional type
List<Student> myListWork = new List<Student>();
Student s2 = new Student("olle", "sundsta");
myListWork.Add(s2);
XMLSerialization.XMLSerialize(@"C:\z3.xml", myListWork, new
Type[0]); // infer T and add no additional type
Console.ReadKey(true);
}
}
}
 
T

Tony Johansson

Hello!
I still have problem with my XML serialize.
The problem is that in the generated XML file there is no information about
the
Info object that is part of the Person Object
The xml file looks this.
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person xsi:type="Student">
<Name>olle</Name>
<Collage>sundsta</Collage>
</Person>
</ArrayOfPerson>

So what do I have to do to be able to get informatiomn about the Info object
in the
generated XML file ?

private void MenuFileExportToXML_Click(object sender, EventArgs e)
{
List<Person> personList = new List<Person>();
string[] itemArray = {"item1","item2","item3"};
Info infoFull = new Info("Test1", itemArray);
List<Info> infoList = new List<Info>();
infoList.Add(infoFull);

Person p1 = new Student("olle", "sundsta",infoList);
personList.Add(p1);
Person[] personArray = personList.ToArray();

XMLSerialization.XMLSerialize<Person[]>(XMLFile, personArray);
}

public class XMLSerialization
{
public static void XMLSerialize<T>(string filePath, T obj)
{
try
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T));
XmlSer.Serialize(fs, obj);
}
}
catch(Exception ex)
{
throw;
}
}
}


[System.Xml.Serialization.XmlInclude(typeof(Student))]
public abstract class Person
{
private List<Info> infoList;
private string name;
public Person() //Default c_tor
{}

public Person(string name, List<Info> myList)
{
this.name = name;
infoList = myList;
}

public string Name
{
get { return name; }
set { name = value; }
}
}

public class Student : Person
{
private string collage;
public Student() //Default C-tor
{}

public Student(string name, string collage, List<Info> myList)
: base(name, myList)
{
this.collage = collage;
}

public string Collage
{
get { return collage; }
set { collage = value; }
}
}

public class Info
{
private string name;
private string[] grade;

public Info() //Default C-tor
{}

public string[] Grade
{
get { return grade; }
set { grade = value; }
}

public Info(string name, string[] grade)
{
this.name = name;
this.grade = grade;
}
}

//Tony
 
A

Arne Vajhøj

I still have problem with my XML serialize.
The problem is that in the generated XML file there is no information about
the
Info object that is part of the Person Object
The xml file looks this.
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person xsi:type="Student">
<Name>olle</Name>
<Collage>sundsta</Collage>
</Person>
</ArrayOfPerson>

So what do I have to do to be able to get informatiomn about the Info object
in the
generated XML file ?
[System.Xml.Serialization.XmlInclude(typeof(Student))]

arghhhh!!!!

public abstract class Person
{
private List<Info> infoList;
private string name;
public Person() //Default c_tor
{}

public Person(string name, List<Info> myList)
{
this.name = name;
infoList = myList;
}

public string Name
{
get { return name; }
set { name = value; }
}
}

The XML serializer works on properties, so you need
to add:

public List<Info> InfoList
{
get { return infoList; }
set { infoList = value; }
}

to get it serialized.

Arne
 
T

Tony Johansson

Arne Vajhøj said:
I still have problem with my XML serialize.
The problem is that in the generated XML file there is no information
about
the
Info object that is part of the Person Object
The xml file looks this.
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person xsi:type="Student">
<Name>olle</Name>
<Collage>sundsta</Collage>
</Person>
</ArrayOfPerson>

So what do I have to do to be able to get informatiomn about the Info
object
in the
generated XML file ?
[System.Xml.Serialization.XmlInclude(typeof(Student))]

arghhhh!!!!

public abstract class Person
{
private List<Info> infoList;
private string name;
public Person() //Default c_tor
{}

public Person(string name, List<Info> myList)
{
this.name = name;
infoList = myList;
}

public string Name
{
get { return name; }
set { name = value; }
}
}

The XML serializer works on properties, so you need
to add:

public List<Info> InfoList
{
get { return infoList; }
set { infoList = value; }
}

to get it serialized.

Arne

Do you find some problem to this attribute
[System.Xml.Serialization.XmlInclude(typeof(Student))]
because it works good.

//Tony
 
A

Arne Vajhøj

Arne Vajhøj said:
I still have problem with my XML serialize.
The problem is that in the generated XML file there is no information
about
the
Info object that is part of the Person Object
The xml file looks this.
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person xsi:type="Student">
<Name>olle</Name>
<Collage>sundsta</Collage>
</Person>
</ArrayOfPerson>

So what do I have to do to be able to get informatiomn about the Info
object
in the
generated XML file ?
[System.Xml.Serialization.XmlInclude(typeof(Student))]

arghhhh!!!!

public abstract class Person
{
Do you find some problem to this attribute
[System.Xml.Serialization.XmlInclude(typeof(Student))]
because it works good.

It works.

But it is not good OO to have a super class knowing
about its sub classes.

I like the idea of having the code that calls the
XML serializer specify the extra classes.

A possible alternative is to have your serialization
wrapper do some magic.

A la:

public class XMLSerialization
{
public static void XMLSerialize<T>(string filePath, T obj)
{
HashSet<Type> addtyp = new HashSet<Type>();
if(obj is ICollection<T> || obj is Array)
{
foreach(object elm in (IEnumerable)obj)
{
addtyp.Add(elm.GetType());
}
}
try
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T),
addtyp.ToArray());
XmlSer.Serialize(fs, obj);
}
}
catch(Exception ex)
{
throw;
}
}
}

But fundamentally the XmlSerializer has an unpleasant requirement.

Arne
 
T

Tony Johansson

I used your example with passing the concreate type to the c-tor for xml
serializer and it work good.

//Tony
 
A

Arne Vajhøj

I used your example with passing the concreate type to the c-tor for xml
serializer and it work good.

Actually the code had a few flaws.

Here is an improved version:

public static class XMLSerialization
{
private static void GetAdditionalTypes(object obj,
HashSet<Type> addtyp)
{
addtyp.Add(obj.GetType());
if(obj is IEnumerable)
{
foreach(object elm in (IEnumerable)obj)
{
GetAdditionalTypes(elm, addtyp);;
}
}
}
private static Type[] GetAdditionalTypes(object obj)
{
HashSet<Type> addtyp = new HashSet<Type>();
GetAdditionalTypes(obj, addtyp);
return addtyp.ToArray();
}
public static void XMLSerialize<T>(string filePath, T obj)
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T),
GetAdditionalTypes(obj));
XmlSer.Serialize(fs, obj);
}
}
}

Arne
 
T

Tony Johansson

Arne Vajhøj said:
I used your example with passing the concreate type to the c-tor for xml
serializer and it work good.

Actually the code had a few flaws.

Here is an improved version:

public static class XMLSerialization
{
private static void GetAdditionalTypes(object obj, HashSet<Type>
addtyp)
{
addtyp.Add(obj.GetType());
if(obj is IEnumerable)
{
foreach(object elm in (IEnumerable)obj)
{
GetAdditionalTypes(elm, addtyp);;
}
}
}
private static Type[] GetAdditionalTypes(object obj)
{
HashSet<Type> addtyp = new HashSet<Type>();
GetAdditionalTypes(obj, addtyp);
return addtyp.ToArray();
}
public static void XMLSerialize<T>(string filePath, T obj)
{
using (FileStream fs = new FileStream(filePath,
FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T),
GetAdditionalTypes(obj));
XmlSer.Serialize(fs, obj);
}
}
}

Arne

It doesn't compile and it's not possible to use method ToArray on addtyp.
I just wonder you say the the previous version had a few flaws in what way.

Have you some good suggestion how to fix the compile error.
When I do the XML deserialize I don't have obj so I think I stick to the old
version.

//Tony

//Tony
 
A

Arne Vajhøj

Arne Vajhøj said:
I used your example with passing the concreate type to the c-tor for xml
serializer and it work good.

Actually the code had a few flaws.

Here is an improved version:

public static class XMLSerialization
{
private static void GetAdditionalTypes(object obj, HashSet<Type> addtyp)
{
addtyp.Add(obj.GetType());
if(obj is IEnumerable)
{
foreach(object elm in (IEnumerable)obj)
{
GetAdditionalTypes(elm, addtyp);;
}
}
}
private static Type[] GetAdditionalTypes(object obj)
{
HashSet<Type> addtyp = new HashSet<Type>();
GetAdditionalTypes(obj, addtyp);
return addtyp.ToArray();
}
public static void XMLSerialize<T>(string filePath, T obj)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
XmlSerializer XmlSer = new XmlSerializer(typeof(T), GetAdditionalTypes(obj));
XmlSer.Serialize(fs, obj);
}
}
}

It doesn't compile and it's not possible to use method ToArray on addtyp.

using System.Linq;
I just wonder you say the the previous version had a few flaws in what way.

The test on ICollection<T> was completely wrong.

And it did not recurse.
Have you some good suggestion how to fix the compile error.

See above.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top