Avoiding static variables with Singleton

18,948

Solution 1

One way to use a singleton (lifted from http://msdn.microsoft.com/en-us/library/ff650316.aspx)

using System;

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }

   /// non-static members
   public string Foo { get; set; }        

}

Then,

var foo = Singleton.Instance.Foo;
Singleton.Instance.Foo = "Potential thread collision here.";

Note that the instance member is a static field. You can't implement a singleton without using a static variable, and (I seem to recall - it's been awhile) this instance will be shared across all requests. Because of that, it's inherently not thread safe.

Instead, consider putting these values in a database or other persistent store that's more thread-friendly, and creating a class that interfaces with that portion of your database to provide transparent access.

public static class Foo
{
  public static string Bar
  {
    get { /// retrieve Bar from the db }
    set { /// update Bar in the db }
  }
}

Solution 2

Let's address your statements one at a time:

A colleague of mine told me that I should never use static variables because if you change them in one place, they are changed everywhere.

It seems fairly clear that your colleague means the basic feature of static variables: there is only one instance of a static variable. No matter how many instances of any class you create, any access to a static variable is to the same variable. There is not a separate variable for each instance.

He told me that instead of using static variables I should use Singleton.

This is not good global advice. Static variables and singletons aren't in competition with each other and aren't really substitutes for each other. A singleton is an instance of a class, managed in such a way that only one instance is possible to create. A static variable is similarly tied to exactly one (static) instance of a class, but could be assigned with not only a class instance but any data type such as a scalar. In actuality, to effectively use the singleton pattern, you must store it in a static variable. There is no way to "use a singleton instead of a static variable".

On the other hand, perhaps he meant something slightly different: perhaps he was trying to say that instead of your static class having many different static variables, method, properties and fields (altogether, members) that function as if they were a class, you should make those fields non-static, and then expose the wrapping class as a Singleton instance. You would still need a private static field with a method or property (or perhaps just use a get-only property) to expose the singleton.

I know that Singleton is for limitation of the number of instances of one class to one. How can Singleton help me with static variables?

A static class's variables and a singleton are alike in that they both are to be instantiated once (the former enforced by the compiler and the latter enforced by your implementation). The reason you'd want to use a singleton instead of a static variable inside of a class is when your singleton needs to be a true instance of a class, and not consist simply of the collected static members of a static class. This singleton then gets assigned to a static variable so that all callers can acquire a copy of that same instance. As I said above, you can convert all the different static members of your static class to be instance members of your new non-static class which you will expose as a singleton.

I would also like to mention that the other answers given so far all have issues around thread safety. Below are some correct patterns for managing Singletons.

You can see that an instance of the Singleton class, which has instance (or non-static) members, is created either by static initialization or within the static constructor, and is assigned to the variable _singleton.. We use this pattern to ensure that it is instantiated only once. Then, the static method Instance provides read-only access to the backing field variable, which contains our one, and only one, instance of Singleton.

public class Singleton {
   // static members
   private static readonly Singleton _singleton = new Singleton();
   public static Singleton Instance => _singleton

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

or, the exact same thing but with an explicit static constructor:

public class Singleton {
   // static members
   private static readonly Singleton _singleton; // instead of here, you can...
   static Singleton() {
      _singleton = new Singleton(); // do it here
   }
   public static Singleton Instance => _singleton;

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

You could also use a property default without an explicit backing field (to follow) or in a static constructor can assign the get-only property (not shown).

public class Singleton {
   // static members
   public static Singleton Instance { get; } = new Singleton();

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

Since static constructors are guaranteed to run exactly once, whether implicit or explicit, then there are no thread safety issues. Note that any access to the Singleton class can trigger static initialization, even reflection-type access.

You can think of static members of a class as almost like a separate, though conjoined, class:

  1. Instance (non-static) members function like a normal class. They don't live until you perform new Class() on them. Each time you do new, you get a new instance. Instance members have access to all static members, including private members (in the same class).

  2. Static members are like members of a separate, special instance of the class that you cannot explicitly create using new. Inside this class, only static members can be accessed or set. There is an implicit or explicit static constructor which .Net runs at the time of first access (just like the class instance, only you don't explicitly create it, it's created when needed). Static members of a class can be accessed by any other class at any time, in or out of an instance, though respecting access modifiers such as internal or private.

Solution 3

The whole point of the static modifier is to ensure that the object thus modified is the same wherever it is used as it requires no instantiation. The name originally came about as a static variable has a fixed location in memory and all items referring to it will reference the same memory location.

Now you may wish to use a static field within a class, in which case it exists before the class is instantiated (constructed). There may be instances where you would want this.

A singleton is a different beast. It is a class that is limited to a single instantiation by use of a private constructor and a static property. So in that regard you still can't avoid statics by using a singleton.

Solution 4

To answer the stated question:

It is incredibly stupid (but possible) to create a singleton without a static field.

To do it, you need to use someone else's static field, such as AppDomain.GetData or (in ASP.Net) HttpContext.Application.

Share:
18,948
petko_stankoski
Author by

petko_stankoski

Updated on June 11, 2022

Comments

  • petko_stankoski
    petko_stankoski almost 2 years

    A colleague of mine told me that I should never use static variables because if you change them in one place, they are changed everywhere. He told me that instead of using static variables I should use Singleton. I know that Singleton is for limitation of the number of instances of one class to one. How can Singleton help me with static variables?

  • LoganS
    LoganS over 12 years
    -1 static doesn't involve any instances - it pertains to a class.
  • SLaks
    SLaks over 12 years
    That's not true at all. You can't manage the lifetime of a singleton. Singletons do not help you achieve thread safety. All of your claims (true or not) also apply to static fields.
  • and_the_rand
    and_the_rand over 12 years
  • Steve Rowbotham
    Steve Rowbotham over 12 years
    @JonH A static field or property still holds a single instance as its value.
  • LoganS
    LoganS over 12 years
    @SteveRowbotham that I can agree with- I was more describing a static class more then a static member of a class which has one value...ack ambiguity.
  • SLaks
    SLaks over 12 years
    @SteveRowbotham: Wrong. A property does not hold a single instance; it can return whatever it wants. A field can be [ThreadStatic]
  • ninu
    ninu over 12 years
    I agree with SLaks above. Read this post from a previous question: Design Patterns When to Use the Singleton
  • Steve Rowbotham
    Steve Rowbotham over 12 years
    @SLaks: [ThreadStatic] isn't under discussion. The point I was making is straight-forward - whether you expose a static field directly or via a property there is still an instance.
  • svick
    svick over 12 years
    Static fields don't exist before a class is created. But you can be sure that it exists before any instance of that class is created.
  • svick
    svick over 12 years
    And can you explain how does that help alleviate the “problems” static classes have? Also, your code won't compile, I assume you didn't intend to make Class2 static.
  • petko_stankoski
    petko_stankoski over 12 years
    But the initial class wasn't static. It was normal class which contains methods and variables. Some of the variables are static.
  • Silas
    Silas over 12 years
    svick: Saw that mistake too and corrected it already. Thanks anyway.
  • ChrisBD
    ChrisBD over 12 years
    Where do I say that it exists before a class is created?
  • svick
    svick over 12 years
    You say it exists “before the class is instantiated (constructed)”. I think that's confusing. Classes aren't instantiated, objects that are an instance of the class are.
  • ChrisBD
    ChrisBD over 12 years
    My apologies I thought that by saying "(constructed)" after instantiated that I'd made it clear that a static field exists before a class contructor is executed.
  • svick
    svick over 12 years
    And that's confusing again. What's a “class constructor”? It could be interpreted as static constructor or instance constructor. Although, you would be right in both cases.
  • ChrisBD
    ChrisBD over 12 years
    Well what can I say? In practice does it make any difference? The static constructor is only executed once for a given application domain, whereas the class instance constructor may be executed many times, eitherway the static field exists and is initialized before either of the constructors are executed.
  • Suhas
    Suhas over 12 years
    @jonh There has to be some instance at the core, isn't it? And I was talking more from perspective of control you have over the static as against a singleton.
  • ErikE
    ErikE about 7 years
    Except, can't you get thread safety by assigning the instance variable with a static initializer: private static readonly Singleton instance = new Singleton()? Then your property can just be: public static Instance => instance;. The only difference is that instance is assigned the first time the Singleton class is used in any capacity, not the first time Instance is accessed. This is a minor detail, as any problems this causes can be eliminated by moving the code to its own class so any access to the class does occur only when the singleton can be instantiated.
  • ErikE
    ErikE about 7 years
    I just confirmed that static initializers are guaranteed to run only once per app domain (be careful with static generics though as that's once per generic type). So using a static method instead of a static initializer or static constructor is not a good idea as it brings with it the non-thread-safe problems you mention.
  • Servy
    Servy about 7 years
    The question isn't asking how to create a singleton. This isn't addressing the actual question asked at all.
  • Servy
    Servy about 7 years
    You shouldn't be posting an answer to say that the question doesn't make sense. If you think that the question doesn't make sense, vote to close it as unclear, rather than posting an answer to a question you don't think is understandable.
  • ErikE
    ErikE about 7 years
    @Servy The question as written doesn't make sense, however the asker's confusion is easy to understand and easily correctable. Do you have a resource on meta.stackexchange that supports your position that "the question doesn't make sense as written"? In any case, I will reword to say that the asker's statements make some invalid assumptions, which I can help correct for him.
  • Servy
    Servy about 7 years
    I don't need to prove to you that the question doesn't make sense. You are the one saying that the question doesn't make sense, both in your answer (on multiple occasions) and in your comment.
  • ErikE
    ErikE about 7 years
    @Servy I wasn't asking you to prove that the question doesn't make sense. I was trying to ask you why your opinion that "you shouldn't post an answer to say a question doesn't make sense" conforms to community standards in the stackexchange network and on stackoverflow specifically (as I've never heard that before). In any case, I have removed all references to "this doesn't make sense", and in fact, have to thank you for your push-back as I think my answer is now improved--I think I've now hit on the most likely advice the colleague was trying to give and explained how to do that.
  • Servy
    Servy about 7 years
    You really need me to explain to you why you shouldn't answer a question that doesn't make sense? There's a specific close reason for questions that don't make sense, "Unclear what you're asking". When it's unclear what a question is asking, you should use that close reason. While you've re-worded your answer, you're still indicating that the question is unclear by saying that you find the question confusing, that you're having to guess at what it's asking, etc.
  • ErikE
    ErikE about 7 years
    I changed my mind. I think the question makes sense now. And I think the question and answer add value, even if the original asker wasn't 100% clear. He was still 80% clear, and explaining the difference between static and a singleton should clear up any confusion.
  • ErikE
    ErikE about 7 years
    @Servy Are you going to vote down the other answers on the page that have the same problems mine do (in your mind)? Is there a reason you singled out my answer above the others besides that it is a new answer? If you think the question is that unclear, you can cast your vote to close, right?
  • ErikE
    ErikE about 7 years
    Yup, I did notice. So now, my comment helps all those people who come to this question looking for current answers, instead of leaving them in the obsolete/archaic land of trying to use old code on new frameworks! It's a win all around, right? I didn't down-vote you. It was good information for the time.
  • ErikE
    ErikE about 7 years
    If you like I'll delete and reword to avoid saying "not a good idea" and can say instead "there is now a better way that avoids all thread safety issues".
  • ErikE
    ErikE over 3 years
    The GetInstance method here is not thread-safe and could yield multiple instances of the same class, because another thread's execution of GetInstance could also check that instance == null before either thread sets instance to new Class2(). Best to use static initialization instead of trying to sychronize, which is full of pitfalls.