181

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.

3
  • 1
    If you're interested, I found how to create objects without needing the constructor (see update) - but this won't help XmlSerializer at all - it still demands it. Useful for custom code, maybe. Dec 24, 2008 at 17:18
  • 1
    XmlSerializer requires a default parameterless constructor for deserialization. Aug 14, 2015 at 13:25
  • The declaration of the parameterless constructor is not required. Once a parameterized constructor is declared, the parameterless constructor must also be declared.
    – H2ONaCl
    Feb 27, 2021 at 2:15

6 Answers 6

262

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.

8
  • 1
    Oh, so, I can make the parameterless ctor private or internal and the serialization still works. Thanks for your answer. Nov 6, 2008 at 5:39
  • 2
    Yes I do it often, though I've come to accept that public parameterless constructors are great because they allow you to use "new()" with generics and the new initialization syntax. For parametered constructors use static factory methods or the builder pattern implementation.
    – cfeduke
    Nov 6, 2008 at 6:14
  • 19
    The accessibility tip is a good one, but your explanation makes no sense for serialization. An object needs to be created only for de-serialization. I'd hazard a guess that the type-check code is built into the XmlSerializer constructor because a single instance can be used both ways. Jan 18, 2009 at 11:05
  • 8
    @jwg One example is when you're sending your XML to a web service of some sort and are not interested in receiving those objects in your own component. Mar 7, 2013 at 9:49
  • 5
    Keep in mind that even if you make your parameterless constructor private or internal, all of your properties whose values were serialized must have public setters.
    – chrnola
    Jun 10, 2014 at 20:09
77

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.

9
  • Thanks for the tip about FormatterServices.GetUninitializedObject(Type). :) Feb 4, 2009 at 9:23
  • 6
    Heh; turns out that I don't follow my own advice; protobuf-net has (optionally) allowed FormatterServices usage for ages Sep 24, 2012 at 8:39
  • 1
    But what I don't understand is, in the case no constructor is specified, the compiler creates a public parameterless constructor. So why isn't that good enough for the xml deserialization engine?
    – toddmo
    Jan 8, 2015 at 15:31
  • If I want to deserialize XML and initialize certain object using their constructor (so that the elements/attributes are provided via the constructor), is there ANY way to achieve this? Isn't there a way to customize the serialization process so that it builds the objects using their constructors? Nov 17, 2017 at 12:37
  • 1
    @Shimmy nope; that's not supported. There is IXmlSerializable, but a: that happens after the constructor, and b: it is very ugly and hard to get right (especially deserialization) - I strongly recommend against trying to implement that, but : it won't allow you to use constructors Nov 17, 2017 at 13:29
11

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.

2
  • 2
    Lol you say, For no good reason whatsoever, then go on to say, 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. If it doesn't know what parameters to pass to a constructor, then how would it know what parameters to pass to a factory? Or which factory to use? I can't imagine this tool being more straightforward to use - you want a class deserialized, then let the deserializer make a default instance and then populate each field you tagged. Easy.
    – Chuck
    May 12, 2020 at 18:12
  • 1
    @Chuck you might want to ask another StackOverflow question "how does a factory method help me with constructor parameters" and let me know, I will answer it for you.
    – Mike Nakis
    Aug 3, 2020 at 10:29
3

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.

0

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.

0

I have this issue for error for serialization

I add a parameterless constructor to class and it's solved.

public Product(int code, string name) { Code = code; Name = name;//constructor elements }

public Product() {///// }

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.