views:

199

answers:

8

I created a class which allows access to global access to a variable while only creating it once, essentially a singleton.

However, it doesn't match any of the 'correct' ways to implement a singleton. I assume that it's not mentioned because there is something 'wrong' with it but I can't see any problem with it other then the lack of lazy initialization.

Any thoughts?

static class DefaultFields
{
    private static readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "defaultFields.ini");
    private static readonly IniConfigSource Ini = GetIni();               

    /// <summary>
    /// Creates a reference to the ini file on startup
    /// </summary>
    private static IniConfigSource GetIni()
    {
        // Create Ini File if it does not exist
        if (!File.Exists(IniPath))
        {
            using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew))
            {
                var iniConfig = new IniConfigSource(stream);
                iniConfig.AddConfig("default");
                iniConfig.Save(IniPath);
            }
        }

        var source = new IniConfigSource(IniPath);
        return source;
    }

    public static IConfig Get()
    {
        return Ini.Configs["default"];
    }

    public static void Remove(string key)
    {
        Get().Remove(key);
        Ini.Save();
    }

    public static void Set(string key, string value)
    {
        Get().Set(key, value ?? "");
        Ini.Save();
    }
}
+2  A: 

All the methods on your class are static, so you are hiding the single instance from your users. With the singleton pattern the single instance is exposed via a public property usually called Instance (in other languages like Java it might be a method called getInstance or similar).

alt text

Your code is not wrong - it's just not the singleton pattern. If you wish to implement a singleton I would recommend Jon Skeet's article Implementing the Singleton Pattern in C#.

Mark Byers
+5  A: 

It doesn't follow the usual singleton patterns as your class is static and just controls access to static variables.

Where as a singleton is normally a static single instance of a class where the only static functions are that to create and access the singleton that stores variables as normal non static member variables.

Meaning the class could quite easily be changed or made to be instanced more then once but yours cannot

Tristan
I was trying to avoid declaring 'IniConfigSource' in a few different places so I just declared it in a single class and just that instead. Being able to just use Default.Get() and etc. rather having to define those variables again and again was my goal.I understand how static classes and such work normally, I was just confused at how static variables worked and just figured that what I had done must be a type of singleton.Since it's not a singleton and I don't have any particular desire to make it one, I guess that it's fine as it is, except for adding some locking as 'rwmnau' suggests.
John
+2  A: 

The biggest problem I see is that you're not doing any SyncLock-ing around writes to your INI file - multiple threads that attempt to write values at the same time could end up with unpredictable results, like both making writes and only one persisting (or multiple threads attempting to write the file at once, resulting in an IO error).

I'd create a private "Locking" object of some kind and then wrap the writes to your file in a SyncLock to ensure that only one thread at a time has the ability to change values (or, at the very least, commit changes to the INI file).

rwmnau
I agree, the lack of locking is likely a problem. It's possible that the `IConfig` implementation performs locking within its Remove and Set methods, but since this code doesn't know what that implementation is, I'd say that the DefaultFields class should perform the locking itself.
Dr. Wily's Apprentice
+1 Good idea thanks.
John
+4  A: 

You are right about the singleton, its a class with a unique instance that provides global access.

It might seem like a static class but usually its implemented in a different way.

Also bear in mind that this pattern should be used with some precaution, as its really hard to refactor out a singleton once its deep in the code. Should be used primarily when you have hardware constraints or are implemented unique points of access to a factory. I would try to avoid it whenever possible.

An example of an implementation is as follows:

public class A
{
    /// <summary>
    /// Unique instance to access to object A
    /// </summary>
    public static readonly A Singleton = new A();

    /// <summary>
    /// private constructor so it can only be created internally.
    /// </summary>
    private A()
    {
    }

    /// <summary>
    /// Instance method B does B..
    /// </summary>
    public void B()
    {
    }
}

And could be used like

A.Singleton.B()

Hope that helps.

Nuno Ramiro
A: 

That's not really a singleton, it's a static class.

In many ways, static classes are similar to singleton's, true. But static classes can't implement interfaces, can't inherit functionality from a base class, and you can't carry a reference to them.

Toby
A: 

Why the readonly on the Ini field?

But if you want implement the singleton pattern, it's something like this:

static DefaultFields
{
    private readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "defaultFields.ini");
    private readonly IniConfigSource Ini = GetIni();               

    private static DefaultFields _default;

    public static DefaultFields Default 
    { 
        get { if(this._default == null){ this._default = new DefaultFields(); } return this._default; } 
    }

    private DefaultFields()
    {

    }

    /// <summary>
    /// Creates a reference to the ini file on startup
    /// </summary>
    private IniConfigSource GetIni()
    {
        // Create Ini File if it does not exist
        if (!File.Exists(IniPath))
        {
            using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew))
            {
                var iniConfig = new IniConfigSource(stream);
                iniConfig.AddConfig("default");
                iniConfig.Save(IniPath);
            }
        }

        var source = new IniConfigSource(IniPath);
        return source;
    }

    public IConfig Get()
    {
        return Ini.Configs["default"];
    }

    public void Remove(string key)
    {
        Get().Remove(key);
        Ini.Save();
    }

    public void Set(string key, string value)
    {
        Get().Set(key, value ?? "");
        Ini.Save();
    }
}
Jérémie Bertrand
A: 

I am interested in answers to this question as well. In my opinion, there is a flood of singleton examples that use lazy instantiation, but I think you have to ask yourself if it's really necessary on a case by case basis.

Although this article pertains to Java, the concepts should still apply. This provides a number of examples for different singleton implementations. http://www.shaunabram.com/singleton-implementations/

I've also seen numerous references to the book "Effective Java", Item 71 - use lazy instantiation judiciously. Basically, don't do it unless you need to.

Dr. Wily's Apprentice
A: 

lazy initialization is very important for a singleton class. By declaring your class to be static you implement a static class, not a singleton class.

Numenor