CodeDOM Singleton Pattern

I had this in my head for a while. I think it could be useful… for someone out there :)

using System;
using System.CodeDom;

namespace DotNetZen
{
    /// <summary>
    /// Represents the base declaration of a class as a Singleton.
    /// </summary>
    public class CodePatternSingleton : CodeTypeDeclaration
    {
        public const string InstanceFieldName = "instance";
        public const string InstancePropertyName = "Instance";
        public const string InnerClassName = "InstanceContainer";

        private CodeMemberField instanceField;
        private CodeMemberProperty instanceProperty;
        private CodeConstructor privateConstructor;
        private CodeTypeConstructor staticConstructor;
        private CodeTypeReference selfReference;

        /// <summary>
        /// Initializes a new instance of the CodePatternSingleton class.
        /// </summary>
        /// <param name="name">The name for the new type.</param>
        /// <param name="isLazyLoad">true if the singleton should load the value on first call; false if at type load.</param>
        public CodePatternSingleton(string name, bool isLazyLoad)
            : base(name)
        {
            // Create a self-reference for re-use.
            this.selfReference = new CodeTypeReference(name);

            // Initialize the static containing field.
            this.instanceField = new CodeMemberField(this.selfReference, InstanceFieldName);
            this.instanceField.Attributes &= ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask;
            this.instanceField.Attributes |= MemberAttributes.Private | MemberAttributes.Static;

            // Initialize the static access property.
            this.instanceProperty = new CodeMemberProperty();
            this.instanceProperty.Attributes &= ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask;
            this.instanceProperty.Attributes |= MemberAttributes.Public | MemberAttributes.Static;
            this.instanceProperty.HasGet = true;
            this.instanceProperty.HasSet = false;
            this.instanceProperty.Name = InstancePropertyName;
            this.instanceProperty.Type = this.selfReference;

            CodeObjectCreateExpression initializationExpression = new CodeObjectCreateExpression(this.selfReference);

            this.instanceField.InitExpression = initializationExpression;

            // If we lazy-load, we should use a nested class.
            // Otherwise, we should just assign it to the field.
            if (isLazyLoad)
            {
                CodeTypeDeclaration nestedClass = new CodeTypeDeclaration(InnerClassName);

                // Create a private constructor so no one could initialize an instance of the nested class.
                CodeConstructor nestedPrivateConstructor = new CodeConstructor();
                nestedPrivateConstructor.Attributes &= ~MemberAttributes.AccessMask;
                nestedPrivateConstructor.Attributes |= MemberAttributes.Private;

                // Create a static private constructor so that the nested class is not marked with beforefieldinit.
                CodeTypeConstructor nestedStaticConstructor = new CodeTypeConstructor();

                // Initialize the static access nested property.
                CodeMemberProperty nestedInstanceProperty = new CodeMemberProperty();
                nestedInstanceProperty.Attributes &= ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask;
                nestedInstanceProperty.Attributes |= MemberAttributes.Public | MemberAttributes.Static;
                nestedInstanceProperty.HasGet = true;
                nestedInstanceProperty.HasSet = false;
                nestedInstanceProperty.Name = InstancePropertyName;
                nestedInstanceProperty.Type = this.selfReference;

                nestedInstanceProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, InstanceFieldName)));

                nestedClass.Members.Add(this.instanceField);
                nestedClass.Members.Add(nestedPrivateConstructor);
                nestedClass.Members.Add(nestedStaticConstructor);
                nestedClass.Members.Add(nestedInstanceProperty);

                this.instanceProperty.GetStatements.Add(
                        new CodeMethodReturnStatement(new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(InnerClassName), InstancePropertyName))
                    );

                this.Members.Add(nestedClass);
            }
            else
            {
                this.instanceProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, InstanceFieldName)));

                // Create a static private constructor so that the class is not marked with beforefieldinit.
                this.staticConstructor = new CodeTypeConstructor();

                this.Members.Add(this.instanceField);
                this.Members.Add(this.staticConstructor);
            }

            // Create a private constructor so no one could initialize an instance of the class.
            this.privateConstructor = new CodeConstructor();
            this.privateConstructor.Attributes &= ~MemberAttributes.AccessMask;
            this.privateConstructor.Attributes |= MemberAttributes.Private;

            this.Members.Add(this.privateConstructor);
            this.Members.Add(this.instanceProperty);
        }

        /// <summary>
        /// Gets or sets the name of the type.
        /// </summary>
        public new string Name
        {
            get
            {
                return base.Name;
            }
            set
            {
                base.Name = value;

                // If the name has changed, so should the singleton.
                this.selfReference.BaseType = value;
            }
        }
    }
}

Output (Foo is lazy, Bar isn’t):

public class Foo
{
    private Foo()
    {
    }

    public static Foo Instance
    {
        get
        {
            return InstanceContainer.Instance;
        }
    }

    public class InstanceContainer
    {
        private static Foo instance = new Foo();

        static InstanceContainer()
        {
        }

        private InstanceContainer()
        {
        }

        public static Foo Instance
        {
            get
            {
                return instance;
            }
        }
    }
}

public class Bar
{
    private static Bar instance = new Bar();

    static Bar()
    {
    }

    private Bar()
    {
    }

    public static Bar Instance
    {
        get
        {
            return instance;
        }
    }
}

Updated to be thread safe (For an explanation go to Jon Skeet’s article about Singletons) with two differences (property in lazy load instead of field and no readonly on fields) due to CodeDOM 1.1 limitations.

Advertisements

5 thoughts on “CodeDOM Singleton Pattern

  1. Not thread safe and…why the f^*& would you want to create that monstrosity for such a small amount of resultant code?

    Codedom is usefull for somethings. If you need to create a simple singleton, you need to type 200 characters instead of 5000.

  2. foobar – You’re right, I’ll have to fix the code.

    Chris Martin – This is supposed to be a reusable and maintainable piece of code, so that if you are supposed to create many singletons, you could simply call on it to do the ‘dirty work’ for you. It’s not supposed to appear each time you need a singleton. If you’d like it in DLL shape, just let me know and I’ll post that for you.

    More suggestions are welcome.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s