Why Doesn't the Xmlserializer Need the Type to Be Marked [Serializable]

Why do you have to mark a class with the attribute [serializable]?

First off, you don't have to.

It is simply a marker interface that tells the serializer that the class is composed of items that it can serialize (which may or may not be true) and that is can use the default serialization.

The XMLSerializer has the additional requirement to have a zero parameter constructor to the class.

There are other serializers that use contracts for serialization (such as the DataContractSerializer) - they give you more control over serialization than simply marking a class as Serializable. You can also get more control by implementing the ISerializable interface.

Why isn't my public property serialized by the XmlSerializer?

As mentioned, most properties must have both a getter and setter; the main exception to this is lists - for example:

private readonly List<Foo> bar = new List<Foo>();
public List<Foo> Bar {get { return bar; } } // works fine

which will work fine; however, if XmlSerializer finds a setter - it demands that it is public; the following will not work:

public List<Foo> Bar {get; private set;} // FAIL

Other reasons it might not serialize:

  • it isn't public with get and set (or is readonly for a field)
  • it has a [DefaultValue] attribute, and is with that value
  • it has a public bool ShouldSerializeFoo() method that returned false
  • it has a public bool FooSpecified {get;set;} property or field that returned false
  • it is marked [XmlIgnore]
  • it is marked [Obsolete]

Any of these will cause it not to serialize

C# force subclass to implement Serializable

The short answer is No you can't enforce an Attribute through an interface.
In principle, interfaces are about contracts (behaviour) while serialisation is about state which is not normally reflected in interfaces.

The options you have are:

  • Instead of using an interface for "storable" objects use an abstract class (like StorableBase) that consumer code should inherit from. Main drawback of this is that it restricts the types of classes the consumer code can use with your library. Also note that not all serialization libraries check all the class hierarchy when looking for Serializable attribute and some might check only the concrete class. You can on top of that implement the ISerializable interface on that abstract class to have more control over the serialisation process. See here for details.

  • Roslyn introduced the concept of Code Analyzers. You can create a custom code analyzer that checks at compile time for your rule. See here for more details and an example.

Unable to xml serialize custom object

Apparently you cannot serialize a type that inherits a non serializable type even ifyou do not wish to serialize the non-serializable properties of your derived type.

I think this should be classed as a bug since the who point of interfaces like ISerializable is to specify exactly what it is you inted to serialize by manually implementing the method that handles the serialization.

In any case the solution to my particular scenario was to not bother serializing at all and simply save the information of interest in to viewstate which would then be reused on postbacks to rebuild controls in the exact same state ready for the page based postback events to occur.

Shame this isnt better documented somewhere because although microsoft does document the SaveViewState and LoadViewState methods of the page lifecycle they are very vague about how these events might be used, i'm guessing they are hoping someone in the community might provide an example.

I would post my code but its a nasty hack to get everything working so i don't thing it should be mainstream msdn code.

Ok for a small internal app though :)

Why XML-Serializable class need a parameterless constructor

During an object's de-serialization, the class responsible for de-serializing an object creates an instance of the serialized class and then proceeds to populate the serialized fields and properties only after acquiring an instance to populate.

You can make your constructor private or internal if you want, just so long as it's parameterless.

XML Serialize generic list of serializable objects

I have an solution for a generic List<> with dynamic binded items.

class PersonalList it's the root element

[XmlRoot("PersonenListe")]
[XmlInclude(typeof(Person))] // include type class Person
public class PersonalList
{
[XmlArray("PersonenArray")]
[XmlArrayItem("PersonObjekt")]
public List<Person> Persons = new List<Person>();

[XmlElement("Listname")]
public string Listname { get; set; }

// Konstruktoren
public PersonalList() { }

public PersonalList(string name)
{
this.Listname = name;
}

public void AddPerson(Person person)
{
Persons.Add(person);
}
}

class Person it's an single list element

[XmlType("Person")] // define Type
[XmlInclude(typeof(SpecialPerson)), XmlInclude(typeof(SuperPerson))]
// include type class SpecialPerson and class SuperPerson
public class Person
{
[XmlAttribute("PersID", DataType = "string")]
public string ID { get; set; }

[XmlElement("Name")]
public string Name { get; set; }

[XmlElement("City")]
public string City { get; set; }

[XmlElement("Age")]
public int Age { get; set; }

// Konstruktoren
public Person() { }

public Person(string name, string city, int age, string id)
{
this.Name = name;
this.City = city;
this.Age = age;
this.ID = id;
}
}

class SpecialPerson inherits Person

[XmlType("SpecialPerson")] // define Type
public class SpecialPerson : Person
{
[XmlElement("SpecialInterests")]
public string Interests { get; set; }

public SpecialPerson() { }

public SpecialPerson(string name, string city, int age, string id, string interests)
{
this.Name = name;
this.City = city;
this.Age = age;
this.ID = id;
this.Interests = interests;
}
}

class SuperPerson inherits Person

[XmlType("SuperPerson")] // define Type
public class SuperPerson : Person
{
[XmlArray("Skills")]
[XmlArrayItem("Skill")]
public List<String> Skills { get; set; }

[XmlElement("Alias")]
public string Alias { get; set; }

public SuperPerson()
{
Skills = new List<String>();
}

public SuperPerson(string name, string city, int age, string id, string[] skills, string alias)
{
Skills = new List<String>();

this.Name = name;
this.City = city;
this.Age = age;
this.ID = id;
foreach (string item in skills)
{
this.Skills.Add(item);
}
this.Alias = alias;
}
}

and the main test Source

static void Main(string[] args)
{
PersonalList personen = new PersonalList();
personen.Listname = "Friends";

// normal person
Person normPerson = new Person();
normPerson.ID = "0";
normPerson.Name = "Max Man";
normPerson.City = "Capitol City";
normPerson.Age = 33;

// special person
SpecialPerson specPerson = new SpecialPerson();
specPerson.ID = "1";
specPerson.Name = "Albert Einstein";
specPerson.City = "Ulm";
specPerson.Age = 36;
specPerson.Interests = "Physics";

// super person
SuperPerson supPerson = new SuperPerson();
supPerson.ID = "2";
supPerson.Name = "Superman";
supPerson.Alias = "Clark Kent";
supPerson.City = "Metropolis";
supPerson.Age = int.MaxValue;
supPerson.Skills.Add("fly");
supPerson.Skills.Add("strong");

// Add Persons
personen.AddPerson(normPerson);
personen.AddPerson(specPerson);
personen.AddPerson(supPerson);

// Serialize
Type[] personTypes = { typeof(Person), typeof(SpecialPerson), typeof(SuperPerson) };
XmlSerializer serializer = new XmlSerializer(typeof(PersonalList), personTypes);
FileStream fs = new FileStream("Personenliste.xml", FileMode.Create);
serializer.Serialize(fs, personen);
fs.Close();
personen = null;

// Deserialize
fs = new FileStream("Personenliste.xml", FileMode.Open);
personen = (PersonalList)serializer.Deserialize(fs);
serializer.Serialize(Console.Out, personen);
Console.ReadLine();
}

Important is the definition and includes of the diffrent types.

Class Serialization To XML

XMLSerializer doesn't support Dictionary out of the box. Your UserCollection class has a Dictionary. See this link for a workaround.
Why doesn't XmlSerializer support Dictionary?

Other than that the XMLSerializer requires that your classes have default constructors (UserCollection and User don't) and each of them must have the [Serializable] attribute.



Related Topics



Leave a reply



Submit