Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

Singletons

Everyone is writing singletons and everyone thinks they know what they are doing, but what if they're wrong?

There is at least one scenario where things indeed can go wrong: serialization! SimoneB wrote about it in a blog post but I think she missed something. In fact, in .NET, there are at least two possible approaches to serialization:

While the two are similar - in fact, SoapFormatter and XmlSerializer can produce the same output - the way they work, the interfaces and attributes they rely on, are quite different:

I am assuming you know about singletons; to recall, the singleton pattern, as described in the famous Design Patterns book, is a software technique implemented to allow only a single, well known, object instance of a class. Let's start from the beginning, with a simple singleton class, shall we?

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    private Singleton() { }

    public static Singleton Instance { get { return (instance); } }
}

As you can see, this class cannot be derived from since it's sealed, cannot be instantiated (except if using reflection) because it has a private constructor, and can only be accessed through its static property Instance. But if we serialize it and afterwards deserialize it, we end up with two different instances of this class! This happens because .NET does not have any intrinsic support for singletons, they are written using common OOP techniques, however, it does have intrinsic support for serialization.

Using IFormatter-implementing classes does not work, because the class is not marked with the [Serializable] attribute, so we are protected from that side, but XmlSerializer does not require the use of this attribute in order to allow serialization, so we have a problem. XmlSerializer does, however, rely on interface IXmlSerializable, so if it is implemented, it's methods are called in the course of the serialization process. If we don't want our class to be serialized, we just have to do something on each of this methods that will prevent it from happening: throw an exception!

Here is the protected version of our code:

public sealed class Singleton: IXmlSerializable
{
    private static readonly Singleton instance = new Singleton();

    private Singleton() {}
    public static Singleton Instance { get { return (instance); } }

    XmlSchema IXmlSerializable.GetSchema() { throw(new NotSupportedException()); }
    void IXmlSerializable.ReadXml(XmlReader reader) { throw(new NotSupportedException()); }

    void IXmlSerializable.WriteXml(XmlWriter writer) { throw(new NotSupportedException()); }
}

And that's it! This way, there is no easy way to have two instances of the Singleton class, unless, of course, if using reflection: the two basic serialization methods supported by .NET both fail.

Feedback, including disagreement, is welcome! :-)

Bookmark and Share
Posted: Sep 08 2008, 10:19 AM by Ricardo Peres | with 6 comment(s)
Filed under:

Comments

Joe Chung said:

How about just throwing the exception in the private constructor if instance is not null?

# October 25, 2008 11:25 PM

Ricardo Peres said:

Hi, Joe!

Your are partially right; the problem, IMHO, is: there are ways to instantiate a type without running its constructor, such as when serializing an instance of an object for use with web services. See the FormatterServices.GetSafeUninitializedObject method.

# October 26, 2008 1:42 PM

weblogs.asp.net said:

Singletons.. Peachy :)

# April 6, 2011 9:46 PM

weblogs.asp.net said:

Singletons.. Ho-o-o-o-t :)

# May 1, 2011 7:57 PM

weblogs.asp.net said:

Singletons.. Retweeted it :)

# June 14, 2011 11:50 PM

Bilal said:

That's not what the folks you are critiquing wanted to achieve.  They wanted to be able to serialize objects which contain references to singletons, and then upon deserializing these objects have them once again refer to singletons.  Blocking all serialization is not a viable solution.

Imagine you have a Gender variable operating on a multiton pattern.  You have 1000 person records, each containing a reference to Gender.  In your program you there are just 2 instances of Gender.  Male and Female.  Now you would like to serialize your 1000 Person records to XML, and load them back in another AppDomain, with the knowledge that upon deserialization into the other AppDomain there will once again be only two Gender instances: Male and Female.

Your "solution" is not a solution.

# November 21, 2011 10:30 AM