Why XML-Serializable class need a parameterless constructor
The answer is: for no good reason whatsoever.
Contrary to its name, the XmlSerializer
class is used not only for serialization, but also for deserialization. It performs certain checks on your class to make sure that it will work, and some of those checks are only pertinent to deserialization, but it performs them all anyway, because it does not know what you intend to do later on.
The check that your class fails to pass is one of the checks that are only pertinent to deserialization. Here is what happens:
During deserialization, the
XmlSerializer
class will need to create instances of your type.In order to create an instance of a type, a constructor of that type needs to be invoked.
If you did not declare a constructor, the compiler has already supplied a default parameterless constructor, but if you did declare a constructor, then that's the only constructor available.
So, if the constructor that you declared accepts parameters, then the only way to instantiate your class is by invoking that constructor which accepts parameters.
However,
XmlSerializer
is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters. So, it checks to see if your class has a parameterless constructor, and since it does not, it fails.
So, if the XmlSerializer
class had been written in such a way as to only perform the checks pertinent to serialization, then your class would pass, because there is absolutely nothing about serialization that makes it necessary to have a parameterless constructor.
As others have already pointed out, the quick solution to your problem is to simply add a parameterless constructor. Unfortunately, it is also a dirty solution, because it means that you cannot have any readonly
members initialized from constructor parameters.
In addition to all this, the XmlSerializer
class could have been written in such a way as to allow even deserialization of classes without parameterless constructors. All it would take would be to make use of "The Factory Method Design Pattern" (Wikipedia). From the looks of it, Microsoft decided that this design pattern is far too advanced for DotNet programmers, who apparently should not be unnecessarily confused with such things. So, DotNet programmers should better stick to parameterless constructors, according to Microsoft.
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.
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.
Seems nobody actually read the original post... it is about SERIALIZATION and not DE-... and for this, no constructors are needed or called at all. The issue is simply poor coding practice from Microsoft.