Static variable, Shared variable... does it matter?

Introduction 

Occasionally I am challenged with the task of needing to explain what the difference is between a "regular" variable and a "static" variable (called "Shared" in VB.NET). I use the term "challenged" not because the people I explain to aren't intelligent, but because it honestly is not a concept that is immediately clear for people that haven't had it explained to them before. Many people partially understand the concept of "object oriented" programming. But static variables are sort of like a step backwards from that which gets confusing. Anyway... last night I was working on a Severity A case (i.e. server is down... people are running around in a panic, thousands of dollars per hour are lost, CEO's are standing around looking for people to fire) where I found the root of the problem to be because of a static variable and I was having a tough time getting the concept across to the people I was helping. So I figured I'd see if I could come up with a good explanation here to save some time in the future.

So first... what is an "object"? If you don't know what an "object" is then you have no hope of understanding what a "static object" is.

You may have heard or read somewhere that "everything in .NET is an object." Okay great. But what the heck does that mean? Well, an object is basically like... I don't know... an object! Like a "real" object, as in a "noun". Maybe like a house. A house has parts in it that are always moving (refrigerator perhaps), things that just sit there (the couch), maybe has things that only do something when you turn them on or off (TV or faucet). So a house is an "object" that can have other objects in it. Or maybe it doesn't have other objects in it (house ready to be sold?). It all depends on the particular object that we've designed. Although "House" gives us a basic description of what this object is, there can be many different houses that are all still called "House". This is much the same as a programming object. It is basically a container of a particular format that can have other objects contained within it.

Okay, so let's make a "House" object in pseudo c# terms. It might look like this. 


class House
{
    string StreetAddress;
    string ResidentName;
    int ResidentCount;

   function TurnOn(string itemName)
    {
        if (itemName == "TV")
        {
            // Code to turn on the TV
        }
        else if (itemName == "Washer")
        {
            // Code to turn on the Washer
        }
        else
        {
            // Code to turn on all the Lights
        }
    }
}

Just the layout of a "House" object doesn't tell me a ton about any *specific* house. That's because this "class" is just a description of what a "House" should have. We can "create an instance" of one or more "House" objects like this:


House myHouse = new House();
House yourHouse = new House();
House dogHouse = new House();

The above code has setup a "new" section of memory that is used to store information about a particular House. Then we can perhaps set some of the values of each house:


myHouse.StreetAddress = "123 Street";
myHouse.ResidentName = "Brian Murphy-Booth";
myHouse.ResidentCount = 3;

yourHouse.StreetAddress = "456 Another Street";
yourHouse.ResidentName = "Some Person";
yourHouse.ResidentCount = 5;

dogHouse.StreetAddress = "Back Yard";
dogHouse.ResidentName = "Ollie";
dogHouse.ResidentCount = 1;

And finally... we can call our method to do something.


myHouse.TurnOn("lights");
yourHouse.TurnOn("TV");

As I go around and run the TurnOn("whatever") method of the different House objects that I have, those values affect only that specific "instance" of the "House" that I'm setting the value on. Each "House" has its own space in memory that has its own unique values. Therefore, calling myHouse.TurnOn("Lights") will only effect *my* house. Not yours. That's because there are 3 places in memory that holds an isolated "instance" of House.

Okay. We're almost ready to look at what a "static" object is. But before I do, let's fix up our pseudo class so it looks closer to valid C# syntax.


public class House
{
    public string StreetAddress;
    public string ResidentName;
    public int ResidentCount;
    private bool Initialized;

    public void TurnOn(string itemName)
    {
        if (itemName == "TV")
        {
            // Code to turn on the TV
        }
        else if (itemName == "Washer")
        {
            // Code to turn on the Washer
        }
        else
        {
            // Code to turn on all the Lights
        }
    }
}

You can see that all I've really done is added some "access modifiers" like "public" and "private" to control who can get or set the variable values. The behavior of setting "ResidentName" etc is essentially unchanged. The only difference now is that I've added an "Initialized" variable that can only be set by other methods inside of "House". For example... I cannot do:


myHouse.Initialized = true; // Can't do this

...since it is private. That's not really the important part of this Blog though, so let's move on. What if we "mistakenly" set one of our variables as "static"? Let's look at the following declarations that include that mistake.


public class House
{
    public static string StreetAddress;
    public string ResidentName;
    public int ResidentCount;
    private bool Initialized;

... etc etc...

}

Uh oh... that's trouble. "What will happen?", you ask. Let's look again at our example of setting the values on the different House objects that we've created.


myHouse.StreetAddress = "123 Street";
myHouse.ResidentName = "Brian Murphy-Booth";
myHouse.ResidentCount = 3;

yourHouse.StreetAddress = "456 Another Street";
yourHouse.ResidentName = "Some Person";
yourHouse.ResidentCount = 5;

dogHouse.StreetAddress = "Back Yard";
dogHouse.ResidentName = "Ollie";
dogHouse.ResidentCount = 1;

The end result here would be that "myHouse.StreetAddress", "yourHouse.StreetAddress", and "dogHouse.StreetAddress" would all have a value of "Back Yard". That's because when a variable is "static" there is only ONE version of the StreetAddress variable in all of the memory!! It is no longer associated with some unique "instance" of House. Think of a "static" variable as being similar to calling the local police station. It doesn't matter which House you call them from. The same phone will ring in the police station up the road. Ahh... but if there is only *1* copy of that StreetAddress variable (no "instance" versions) then there is actually a coding mistake above. Attempting to compile the above code would generate a compile error. It can actually only be like this:


House.StreetAddress = "123 Street";
myHouse.ResidentName = "Brian Murphy-Booth";
myHouse.ResidentCount = 3;

House.StreetAddress = "456 Another Street";
yourHouse.ResidentName = "Some Person";
yourHouse.ResidentCount = 5;

House.StreetAddress = "Back Yard";
dogHouse.ResidentName = "Ollie";
dogHouse.ResidentCount = 1;

In reality, since making it "static" means there can only be one copy, StreetAddress cannot be accessed using an "instance" name anymore (such as "myHouse"). There is one and only one version of StreetAddress in all of memory so we just say which object type we're referring to (House is a "type" of object) then set it directly (House.StreetAddress).

Abbreviated Real World Example:

I'll walk you through what was happening with the customer that I was helping last night. The configuration was something like this:

  • ShowInfo.aspx and ShowInfo.aspx.cs
  • DataBaseStuff.cs.
  • In DataBaseStuff there was a "static" SqlConnection *variable* called myConnection
  • In DataBaseStuff there was a "static" SqlCommand *variable* called myCommand
  • In DataBaseStuff there was a "static" *method* named GetDataTable().
  • Page_Load was calling DataBaseStuff.GetDataTable(string userName) to get some data.
  • GetDataTable made use of the static myConnection object to retrieve data from SQL.
  • Page_Load assigned the resulting DataTable to a DataGrid.
  • Personal information for the logged in user was displayed on the web page.

The result? During peak hours for the web site, information for UserA was being shown to UserB. How did this happen?

  • ShowInfo.Page_Load() begins to execute for UserA.
  • ShowInfo.Page_Load() begins to execute for UserB
  • UserA has DataBaseStuff.GetDataTable("UserA") called for them.
  • UserB has DataBaseStuff.GetDataTable("UserB") called for them.
  • UserA has something like "SELECT * FROM Users WHERE username='UserA';" assigned to the static myCommand object.
  • UserB has something like "SELECT * FROM Users WHERE username='UserB';" assigned to the static myCommand object.
  • UserA starts to pull data from SQL.
  • UserB starts to pull data from SQL.
  • Result: Since UserB's SQL query was the last one assigned to myCommand (which remember... there is only one version of this in all of memory), the myConnection object is using UserB's query for both users. UserB sees UserB's data. UserA sees UserB's data too.

Here are some questions I asked my customer after finding the problem.

Me: Why are the myCommand and myConnection variables "static"?
Customer: Because there was a compile error in GetDataTable when they weren't static.
I think: Hmm... not the best of reasons. But okay.

Me: That's because GetDataTable is static. Why is the GetDataTable method "static"?
Customer: Because when it is static I don't have to use "new" when calling it from ShowInfo.aspx.
I think: Okay. That's a valid reason.

Me: Well... that's a good reason to make it static. But... [So then I try for 20 minutes to explain what a static variable is.]

*The* reason you want to make a variable static is for scalability reasons. In my customer's example, it would not make sense to user the same SqlConnection and SqlCommand for multiple users because of the types of problems it could cause. It would, however, make sense to use the same connection string for multiple users. If you had 100 instances of DataBaseStuff in memory, you would not want to waste space by having 100 copies of the same connection string assigned to all 100 versions of DataBaseStuff Instead, we'd make myConnectionString static so that it exists in memory only once (yes, I know what an "interned" string is. For all you experts: don't complicate my example!!).

Summary:

There are many different features of C# (and VB.net). Using "static" methods and variables can be a big plus relative to performance and scalability. The important caveat is just that you make sure you use the features in the way they were intended on being used! Doing something "just because" can cause unexpected results.

I'm interested in your feedback. If my explanation above doesn't make sense, let me know. Leave a comment with your email address and I'll see if there is something I can do to make it easier to understand. All comments must be approved by me first so I'll be sure not to publish your address.

 

11 Comments

  • gud post brian

    but here the problem is due to sqlCommand being static not sqlconnection.

    sqlconnection can very well be static.In fact we can even restrict the sqlconnection instance to one for better performance

    woz say?

  • I am using static variables in my aspx.cs to maintain variables between pageloads of the aspx. Won't each browser get a separate instance of the aspx/aspx.cs so that static variables won't be shared between sessions?

  • Thanks Brian! We recently wrote a big web application for one of our clients, and after everything was done, during a review.. I was shocked..!! almost all the variables had a keyword "static".. across all the pages!! This explaination is too good to convince my team that we are not going the correct way!!

  • A static variable is not "page" specific. It is "AppDomain" specific. The only relation to the "page" would be the path (so to speak) of the variable (MyProject.MyPage.MyVariable for example). Because all users of your application are running in the same AppDomain (i.e. same IIS application folder), then they will all use the same static variable. So... eventually your users are going to see each other's information since they are all sharing that one single static variable.

  • hi very good post.
    Acutally we got the same issue because of static Variable used in the Aspx.cs for assigning ordernumber.
    concurrent user accessing the same page this issue raised in the server.
    now we have removed all the static variables in the page level. but Business layer Still so many methods having static.could you suggest me where static method have to be used?

  • Just came across - good examples. Just a quick note on the response above, the author never said to use static sqlConnection objects - he gave an example recommendation of using a static sql connection string which is a good idea. Big difference between a connection object and the connection string initializer. Using a static connection string is a pretty gauranteed way to use connection pooling as your connection objects should be identical if instantiated from the same connection string.

  • hello brian,

    Excellent Article.

    Is there any difference between Shared and private Shared?
    Same Problem we faced...in my application..?How to solve the problem..

    We declared one variable as shared, to maintain variables between pageloads of the aspx

    can we use private shared ?

    Hope Will give reply

    Thanks
    Sandhya

  • Your article is so good about static variable and anybody can understand very easily the basic fundamental of static variable.Would you please tell me in which situation we should use static variable.

  • Sandhya,

    "Shared" (static) refers to whether a variable is specific to a "new" instance of an object/class or whether it is not specific to a specific instance. "Private" refers to a variable's visibility outside the class. It will often make sense to have a shared variable that is private. Quick example: If you have an array of country names that you want to use to populate a DropDownList then making it static might improve performance and scalability. If you had 30 users on your site, it would be wasteful to have 30 copies of your country list in memory. Being Shared would make it one copy. Then, if only one ASPX page and/or class ever used this country list, it might make sense to hide that list from other classes by making it private. It probably wouldn't hurt to make it public, but private would give your class a cleaner look when programming around it.

    But then again, if there is no "Private" or "Public" etc modifier the default would be to be a private variable anyway. :-)

  • I think the static variables are so "playfully" misused. I guess new developers should read this article posted by Brian to understand the trouble they are getting into if they use statics without thinking.

    Excellent post!!

  • Yes, the method being shared or static is fine because each time you call the method you'll pass get separate objects that are not shared between the users.

Comments have been disabled for this content.