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

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.

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.

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.

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.

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.

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.

Related

How to tell if Type has been generated by the yield return? How to create an instance of this class?

I'm reflecting over an Assembly and there are some types which have been generated by yield return, is there a reliable way to filter them out?
There's no default constructor for the Type generated by yield return. It is a class and not a value type. How to make an instance of this class?
The generated type-name looks like this:
SomeNamespace.RootMode+<GetMouseArrow>d__1, where RootMode is the class name and GetMouseArrow is the function which has yield-return in it.
Use case: Serialization of complete state of a running application, including the state of yield-return statements
UPDATE:
Types generated by the yield return have a single public constructor which takes int as parameter. This is the state variable used to determine where in the function the IEnumerator is.
The generated classes are private and sealed, they implement a set of IEnumerator*/IEnumerable* interfaces.
The generated class has [CompilerGenerated] attribute set to it.
The [CompilerGenerated] is most likely what you want. It's used not just for "iterator methods" (the name of the feature you're describing), but if you're looking to filter out types, you probably want to filter out all compiler-generated types (which would also include types generated for anonymous methods, and for async methods).
As far as instantiating an instance of such a class, you can use reflection, but of course you'll have to identify the parameter to pass and use the appropriate constructor overload. Without the default constructor, the usual serialization techniques won't work; you'll have to implement something yourself to handle this explicitly. I.e. get the appropriate value from within the class instance when serializing, and then pass it to the constructor…of course, to fully restore the state of the class, you'll need to serialize all the private fields and restore those again on deserialization, all via reflection.
I hope the value of implementing this is very high to you, because the cost sure will be. :)

XmlSerializer & Activator.CreateInstance()

Okay, we all know that it is not possible to use the XmlSerializer for classes without a parameterless constuctor as the deserializer will create the object and set all properties. However, by using Activator.CreateInstance() one can instanciate classes without a parameterless constructor. For example we could instanciate the following class:
public class Foo
{
public Foo(string bar){}
}
That class can easily be instanciated with the Activator:
Activator.CreateInstance(typeof(Foo),"some string");
Unfortunantely 'Foo' cannot be serialized using the XmlSerializer as it has no parameterless constructor. Why is there no way to use the XmlSerializer like that:
new XmlSerializer(typeof(Foo)).Deserialize(stream,"some string");
Of course I could implement my own Serializer that simply will store the type and all properites & fields of an object and then will use the Activator to instanciate the object and set the previously stores properties. The question is: would that make sense? I guess there must be a strong reason against because otherwise that would be implemented already, right?!?
XmlSerializer works via C# code-generation and dynamic compilation; because it uses the C# compiler, it is necessary that the code it generates would compile - noting that it must follow the rules as a separate assembly (no internal or private access).
Basically, it wants to use new Foo(), because it literally emits the C# code "new Foo()" which is fed to the compiler.
Yes, it could have chosen to use a different instantiation technique, but: new Foo() is the authors chose to go with - and it is a reasonable default.
Some other serializers choose to use Activator, and others still use sneaky IL techniques that provide direct access to non-public methods without any indirection.

Why can't I serialize readonly fields with XmlSerializer?

XmlSerializer do not serialize readonly fields, readonly properties (only with getter), private fields etc. In addition it will not serialize the object if the class does not have a parameterless constructor. My questions:
AFAIK these problems arise because private (and readonly) fields can not be accessed (and changed) while deserializing. But what if I will not deserialize? Don't I have an option for this?
Because of the same reason (deserialization concerns), it does not serialize the object if the class does not have a parameterless constructor. But when I add a private parameterless constructor it works fine. How?
I do not like to add a parameterless constructor to every class, and make all fields public and non-readonly just to be able to serialize it. For now I am throwing an exception in the private parameterless constructor to prevent the usage. Is there an attribute for constructors which tells the compiler that only authorized calls can be made to that constructor? If not at least I would like to mark it with an attribute which throws the exception if it is called.
That's quite a good question, and I'll try my best to answer:
I believe the reason for the setter as well as the getter is that it's generally assumed if you've only got a getter, then it implies it's not an instance property, it's something that is derived. That would imply if you were to deserialize it (I know you're not doing this) then you could derive this value by setting all the other fields, and therefore serialization doesn't need to care about it.
The reason the parameterless constructor is required is because the type will be created using Reflection. Probably through a call like Activator.CreateInstace(type). This requires a parameterless constructor for the instance to be created, although it probably doesn't matter if it's public or private.
The reason the instance is required is so the fields on it can then be populated with the data retrieved from the XML.
You'll need this constructor, however you could add the ObsoleteAttribute to ensure that it's not called manually, or do as you're doing and make it private.
[Obsolete(true)]
public Foo()
{
}
One way of working around some of these issues may be to implement the IXmlSerializable interface manually, then you have a finer control over serialization but will still need that parameterless constructor.

Why is no constructor needed of the object, deserialized from a json string, using ServiceStack Json Serializer

I wonder why no constructor is necessary to deserialize a json string into a .Net/C# class object instance. I was surprised that the constructor is not invoked at all and removed it and the deserializer still created an object instance from the json string. Is this normal?
(I use the json serializer of ServiceStack)
Germanns answer is not entirely true. It is possible to instantiate an object that has no default constructor without executing any constructor.
This is done with FormatterServices.GetUninitializedObject.
ServiceStack is using this method if it cannot find a default constructor, hence it can deserialize objects that have no default constructor.
Default (no parameters) constructor is created by the compiler if no constructors are specified.
The compiler does that when and only when NO constructors exist. If you create ANY constructor in your class this compiler behaviour will no longer apply.
(Try creating a constructor with at least one parameter to see what will happen)
Deserialization will involve two steps - create empty object using default (no parameters) constructor and than set all values. If you class does NOT have default (no parameters) constructor - either created by yourself explicitly or by the compiler - deserialization will fail.
Deserialization never uses parametrised constructors as it is impossible for it to guess the correct constructor to use. Example: deserialization can not distinguish between Constructor(String parameter1) and Constructor(String parameter2)

Why does XmlSerializer requires the classes of the serialized object declared as public?

It's totally well known that in order to be able to serialize your objects using XmlSerializer you have to declare their classes as public -otherwise you get an InvalidOperationException. The question here is why? I Googled and I found out that XmlSerializer actually generates and compiles a brand new assembly and then uses this assembly to serialize your objects. The question is, still, why does it require the class to be public, while it's easy to get access to internal types in my assembly using reflection?
Quite simply because it doesn't use reflection in order to serialise/deserialise your class - it access the public properties (and classes) directly.
Using refleciton to access members would be extremely expensive so instead, as you mention in your question, it generates a serializer class once using reflection, caches it*, and from this point onwards uses direct member access.
I should qualify this: it only generates a serializer once and caches it for certain constructor overloads on the XmlSerializer. For others, it re-generates the serializer class every time you create an instance of the serializer.
As long as you use the vanilla constructor you are alright:
XmlSerializer ser = new XmlSerializer(typeof(MyType));
The simple reason is because it's been that way since Day 1.
Also, Reflection is expensive. Why do it if you don't have to?
Also, the XML Serializer isn't intended to serialize every class in the world. It's meant to serialize classes designed to be serialized. As such, it's no great burden to make sure the data you want is in public fields and properties of a public class with a public parameterless constructor.
It's only when you try to serialize a type that was not designed to be serialized that you run into trouble.

Categories