Saturday, February 7, 2009

XML Serialization Tip: Hiding default constructor

Here is a quick tip. You all know that to serialize and deserialize an object in XML you need a default (parameter less) constructor. But sometimes you don’t want anybody to use it other than the serializer itself.

By making the default constructor obsolete you can make sure no code will directly call it.

public class MyClass
{
	[Obsolete("For XML Serialization Only", true)]
	public MyClass()
	{
		// Needed for XML serailisation
	}

	public MyClass(string initialValue)
	{
		// ...
	}

	// ...
}

Don’t forget to specify true as the second argument to the Obsolete attribute. This will raise a compilation error if this constructor is called directly. I insist on “directly” because nothing will prevent someone to use reflection to call it. XML Serialisation can occur because it uses reflection to do it.

9 comments:

Anonymous said...

Another way to do that is to mark the parameterless constructor as private!

Eric De C# said...

No you can't. For default XML serialization to work you must have a public default constructor. You can build your own XmlSerializer but it's a lot more work.

Kinich Ahau said...

I would suggest another approach to do this, usually the user if the member is not documented, nor visible to intellisense won't know about them.

Conviniently the framework includes the wollowing attribute so intellisense will ignore it:

System.ComponentModel.EditorBrowsableAttribute

Especifing System.ComponentModel.EditorBrowsableState.Never should make the trick!

[EditorBrowsable(EditorBrowsableState.Never)] public string[] Types { get; set; }

Eric De C# said...

Yes intellisense will ignore it but you will still be able to use it anyway. The goal here is to make your code foul proof.

Mikey B said...

Unfortunately the Obselete attribute won't actually succeed in making the code fool (foul??) proof. Just because a method is obselete doesn't mean you can't call it, nor that it is hidden from the types public interface. It merely means the compiler will generate an error if you try to call it directly. Consider, for example, Acivator.CreateInstance(...).

Hiding methods behind Obsolete and EditorBrowsable attributes is kinda like "security through obscurity". It provides only the most basic level of protection... it certainly isn't fool proof.
Never underestimate the power of a determined idiot!

I believe the first commentator was correct is her/his assertion that you can use a non-public constructor though. There is nothing in the documentation which indicates the default constructor needs to be public (merely that it exists).
I would be interested in seeing an example where having a private does not work, though.

Alré Thomas said...
This comment has been removed by the author.
Anonymous said...

Eric is correct and his method is the best I have seen so far. I see a lot of people is under the misconception that you can serialize an object to XML with a private parameter-less constructor. I was sincerely hoping that it was me that was wrong but I have tried multiple times with all the different methods available to no avail. Binary serialization don't need a public constructor. XML Serialization for some reason do. ps. This is also when using .NET 2.0. Don't know if this changed in later versions. Feel free to ask for example code if you don't believe me.

jitumandalia said...

I have just tried and XML serialization with private default constructor worked without any issue for ASP.Net MVC apps with .Net 2.0

jflood said...

Hey Eric, Anon is right, private default ctor works and is a complete solution.

I think you should update your post so that others who do not read comments can benefit from this.

Keep up the good work