c# - Why XML-Serializable class need a parameterless constructor


Translate

I'm writing code to do Xml serialization. With below function.

public static string SerializeToXml(object obj)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);
        return writer.ToString();
    }
}

If the argument is a instance of class without parameterless constructor, it will throw a exception.

Unhandled Exception: System.InvalidOperationException: CSharpConsole.Foo cannot be serialized because it does not have a parameterless constructor. at System.Xml.Serialization.TypeDesc.CheckSupported() at System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo sourc e, Boolean directReference, Boolean throwOnError) at System.Xml.Serialization.ModelScope.GetTypeModel(Type type, Boolean direct Reference) at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type , XmlRootAttribute root, String defaultNamespace) at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultName space) at System.Xml.Serialization.XmlSerializer..ctor(Type type)

Why must there be a parameterless constructor in order to allow xml serialization to succeed?

EDIT: thanks for cfeduke's answer. The parameterless constructor can be private or internal.


All Answers
  • Translate

    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.


  • Translate

    This is a limitation of XmlSerializer. Note that BinaryFormatter and DataContractSerializer do not require this - they can create an uninitialized object out of the ether and initialize it during deserialization.

    Since you are using xml, you might consider using DataContractSerializer and marking your class with [DataContract]/[DataMember], but note that this changes the schema (for example, there is no equivalent of [XmlAttribute] - everything becomes elements).

    Update: if you really want to know, BinaryFormatter et al use FormatterServices.GetUninitializedObject() to create the object without invoking the constructor. Probably dangerous; I don't recommend using it too often ;-p See also the remarks on MSDN:

    Because the new instance of the object is initialized to zero and no constructors are run, the object might not represent a state that is regarded as valid by that object. The current method should only be used for deserialization when the user intends to immediately populate all fields. It does not create an uninitialized string, since creating an empty instance of an immutable type serves no purpose.

    I have my own serialization engine, but I don't intend making it use FormatterServices; I quite like knowing that a constructor (any constructor) has actually executed.


  • Translate

    First of all, this what is written in documentation. I think it is one of your class fields, not the main one - and how you want deserialiser to construct it back w/o parameterless construction ?

    I think there is a workaround to make constructor private.