Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Must Remember: 9 Key Concepts to Keyword ‘Static’

0.00/5 (No votes)
29 Apr 2015 1  
Article summarizes some of the key concepts around the keyword ‘Static’ which every developer must remember.

Preface

When we talk about the Object oriented Programming (OOP) methodology, suddenly our mind strikes with Abstraction, Encapsulation, Polymorphism and Inheritance. And as coffee blends more people on table, discussion tends to stretch one level more with Data hiding, overloading, overriding, abstract classes and sealed classes. With my experience, every time I have revisited these Jargons, I came across the unknown corner which left me surprised. One of such keyword is "Static". It starts with a simple concept of "Sharing" but in depth, it leads to some surprising results. Today, we will explore these concepts.

Disclaimer: This article covers concepts of Static keyword with respect to C# programming language. Some of these concepts may not be applicable to other high level programming languages.

Before We Begin…

For those of you who have little or less idea about the keyword static, I would like to brush upon the concepts.

For example, we have following DistanceConverter class which has one of the methods called GetDistanceInKM() which accepts distance in miles and converts to KM (kilometers).

C#
/// <summary>
/// Converts distance from one unit to another
/// </summary>
public class DistanceConverter
{
    float _multiplier = 1.60934F;

    /// <summary>
    /// Return the distance in KM
    /// </summary>
    /// <param name="distanceInMiles">Distance in Miles</param>
    /// <returns></returns>
    public float GetDistanceInKM(float distanceInMiles)
    {
        return (_multiplier * distanceInMiles);
    }
}

Main() function:

C#
class Program
{
    static void Main()
    {
        DistanceConverter objD1 = new DistanceConverter();
        Console.WriteLine("D1:" + objD1.GetDistanceInKM(2));

        DistanceConverter objD2 = new DistanceConverter();
        Console.WriteLine("D2:" + objD2.GetDistanceInKM(3));

        DistanceConverter objD3 = new DistanceConverter();
        Console.WriteLine("D3:" + objD3.GetDistanceInKM(4));

        Console.ReadLine();
    }
}

As you can see from Main(), we have created multiple objects of class DistanceConverter. Here is the behind scene memory allocation.

Image 1

As you can see, objects objD1, objD2 and objD3 all are using the same field and the same method. It’s just that they happen to pass different values of distance in miles to get the distance in KM. Taking a closer look, the value for the field _multiplier is the same. If we were to create another 100, 200 or 1000 of objects, the value of field _multiplier would have been same repeated all over. But wait, that’s improper use of memory! In the true sense, it would be nice to have 1 copy of _multiplier shared across all instances of the class. Just like it is shown in the diagram below:

Image 2

And hence the concept, the concept of sharing referred as static or shared (in VB.NET world) field or variable. Similarly we can have constructors, methods, properties or even whole classes shared. If we were to achieve this programmatically, we will denote with static keyword as shown below:

C#
/// <summary>
/// Converts distance from one unit to another
/// </summary>
public class DistanceConverter
{
    static float _multiplier = 1.60934F;

    /// <summary>
    /// Return the distance in KM
    /// </summary>
    /// <param name="distanceInMiles">Distance in Miles</param>
    /// <returns></returns>
    public float GetDistanceInKM(float distanceInMiles)
    {
        return (_multiplier * distanceInMiles);
    }
}

In the example above, _multiplier is Static and hence referred to as Static member of the class while GetDistanceInKM() method is Non-static and hence referred as Instance member of class. With this example, we have tried to see the significance of keyword static. Let’s jump back to our main discussion and let’s discuss the key concept about keyword static that are worth remembering.

1. Applicability

A class can be static but Structure and Interface cannot be. Similarly, Constructor, Fields, Properties and Methods can be static but Destructors cannot be.

We can have Static Class, Fields, Property, Constructor and Methods:

C#
/// Static class
static class StaticClass
{
    //Some class members
}

public class SomeClass
{
    //Static Field
    static int intstatic = 0;

    //Static Property
    public static string StaticProperty { get; set; }

    //Static Constructor
    static SomeClass()
    { }

    //Static Method
    public static void DoSomething()
    {
        Console.WriteLine(intstatic);
    }
}

but we cannot have Static Interface, Structure or Destructor:

C#
/// Trying to declare static Interface
static interface IStaticInterface
{
    //some interface members
}

/// Trying to declare static structure
static struct StaticStruct
{
    //some structure member
}

/// Some Random class
class SomeClass1
{
    /// Trying to declare static Destructor
    static ~SomeClass1()
    { }
}

If we try to create one, will get the following compilation error:

"The modifier 'static' is not valid for this item"

Later, we will also discuss why such implementation does make sense.

2. Access Modifiers

Static Constructor does not have access Modifiers. Other Static elements do.

We can have static classes, fields, property and methods denoted with access modifier. But if you do so with static constructor:

C#
//Static class with Access Modifier
public class SomeClass
{
    //Static Field with Access Modifier
    public static int intstatic = 0;

    //Static Property with Access Modifier
    public static string StaticProperty { get; set; }

    //Trying to declare static Constructor with Access Modifier
    public static SomeClass()
    { }

    //Static Method with Access Modifier
    public static void DoSomething()
    {
        Console.WriteLine(intstatic);
    }
}

It will result in compilation error.

"Access modifiers are not allowed on static constructors"

Also, if you notice, so far I have used word constructor but not constructor(s). Why? Will see next.

3. Unique Static Constructor

A class can have only one Static Constructor and that too parameterless.

If we follow the overloading, we can have multiple constructors each having a different signature. If we try to mark them static,

C#
public class SomeClass
{
    /// Static Constructor without parameters
    static SomeClass()
    {
        //Do something
    }

    /// Trying to declare Static Constructor with parameters
    static SomeClass(int input)
    {
        //Do something
    }
}

We will get a compilation error:

"A static constructor must be parameterless"

So, a class cannot have static constructor with Parameter(s) and hence it can have only one static constructor and that too parameterless.

4. Priority - Static vs Instance Constructor

Static Constructor executes well before instance constructor and only executes once.

Let’s create one simple program to prove this:

C#
public class SampleClass
{
    //Static Constructor
    static SampleClass()
    {
        Console.WriteLine("This is SampleClass Static Constructor.");
    }

    //Instance Constructor
    public SampleClass()
    {
        Console.WriteLine("This is SampleClass Instance Constructor.");
    }
}

class Program
{
    static void Main()
    {
        SampleClass objC1 = new SampleClass();
        SampleClass objC2 = new SampleClass();
        SampleClass objC3 = new SampleClass();

        Console.ReadLine();
    }
}

Output of this program is as follows:

Image 3

As you can see, static constructor was first to execute and only executes once. We will again revisit this point. Especially the word “well before”.

5. Accessibility

Instance members are accessed with class object outside the class definition and ‘this’ keyword inside the class definition while static members can be directly accessed with class name outside and inside of definition.

This is an important point and it makes sense also as static members are independent of instance objects.

C#
public class SampleClass {
    public string instanceMsg = "This is instance Field.";
    public static string staticMsg = "This is static Field";

    public SampleClass()
    {
        // Access within class definition
        Console.WriteLine("Within class instanceMsg:{0}",
                            this.instanceMsg);
        Console.WriteLine("Within class staticMsg:{0}",
                            SampleClass.staticMsg);
    }
}

class Program
{
    static void Main()
    {
        SampleClass ObjS1 = new SampleClass();

        // Access outside class definition
        Console.WriteLine("From Main Program instanceMsg: {0}",
                            ObjS1.instanceMsg);
        Console.WriteLine("From Main Program staticMsg: {0}",
                            SampleClass.staticMsg);

        Console.ReadLine();
    }
}

We will revisit this in upcoming sections.

6. Compatibility – Static vs Instance Members/Container

Instance member cannot be created or accessed from Static container while static members can be created or accessed from Instance container.

Subheading is not clear! Don’t worry. Let’s understand this with some examples.

In Scenario 1, we are trying to access static field iInc within Instance method DoSomething().

C#
// This compiles successfully
public class InstanceContainerStaticMember
 {
     static int iInc = 0;

     // Instance Container Method
     public void DoSomething()
     {
         // Static Member
         iInc++;
         Console.WriteLine("iInc:{0}", iInc);
     }
 }

On the other hand, in Scenario 2, we tried to access instance member iInc within static method DoSomething().

C#
// This will result in compilation Error
public class StaticContainerInstanceMember
 {
     int iInc = 0;

     /// Static Container Method
     public static void DoSomething()
     {
         //Instance Member
         iInc++;
         Console.WriteLine("iInc:{0}", iInc);
     }
 }

But when we compiled, Scenario 2 throws compilation error.

"An object reference is required for the non-static field, method, or property"

So the compilation error is clear that we cannot access instance member from static container. Why? We will explore this with an example. Recall point 5. According to that, Static members are referred with class name. So in the example below:

C#
public class SampleClass {
    private int _id;

    public SampleClass(int ID)
    {
        _id = ID;
    }

    public static void StaticMethod()
    {
        //I want to access _id but who will provide me
    }
}
class Program
{
    static void Main()
    {
        SampleClass s1 = new SampleClass(1);
        SampleClass s2 = new SampleClass(2);
        SampleClass s3 = new SampleClass(3);

        //What will be the value for this s1, s2 or s3
        SampleClass.StaticMethod();
    }
}

We have SampleClass which has non Static field _id and static method StaticMethod() which wants to access _id. In the Main() program, there are 3 objects s1, s2 and s3 created of class SampleClass. And hence the value for _id will be 1,2 and 3 for object s1, s2 and s3 respectively. Now when a program makes calls to SampleClass.StaticMethod(). Since it is called with class name, if the static method was allowed access _id, which _id value it should return, s1, s2 or s3? No it cannot return any as StaticMethod() is independent of class objects and hence independent of instance member and so the compiler shows the error. This holds true for Static classes as well. Static class cannot have instance member such as fields, property, constructor or methods. Try yourself!

7. Object Creation and Instantiation

Static class object can neither be created nor instantiated.

As static class cannot have instance members, it cannot be instantiated. In the example below, we are trying to create the instance of the class SampleClass.

C#
public static class SampleClass {
    //static class members
}

class Program
{
    static void Main()
    {
        //This statement will result compilation error.
        SampleClass s1 = new SampleClass();
    }
}

We get the compilation error:

"Cannot declare a variable of static type 'SampleClass'"
"Cannot create an instance of the static class 'SampleClass'"

Important

While building an application, you will come across code blocks which are repetitively used in the application but don’t belong to specific code hierarchy. Usually developers refer to them as utility functions. They serve general utility purpose in application. You certainly want to modularize these codes. At the same time, you want to access these functions without any object creation. Static classes are great to organize these functions. In Microsoft.NET framework, one of the great examples of utility class is Math class. See the screenshot below:

Image 4

8. Inheritance

Static class cannot be part of inheritance. It cannot serve as base class, derived class or implement the interfaces.

Yes, that’s true. As always, let's see by the following examples.

Case 1: Static class cannot be a base class:

C#
public static class BaseClass
{
    //Class member goes here
}
public class DeriveClass : BaseClass
{
    //Class member goes here
}

Compilation error

"Cannot derive from static class 'BaseClass'"

Case 2: Static class cannot be derived class:

C#
public class BaseClass
{
    //Class member goes here
}
public static class DeriveClass : BaseClass
{
    //Class member goes here
}

Compilation error:

"Static class 'DeriveClass' cannot derive from type 'BaseClass'. Static classes must derive from object."

Case 3: Static class cannot implement interfaces:

C#
public interface IInterface
{
    //Interface member goes here
}
public static class DeriveClass : IInterface
{
    //Class member goes here
}

Compilation error:

"'DeriveClass': static classes cannot implement interfaces"

That’s clear but one question. As we have seen that the static class cannot be part of inheritance hierarchy, then what will happen to protected members in the static class? The answer is Static class cannot have protected members. If you declare the one,

C#
public static class StaticClass
{
    //Protected is not allowed here
    protected static int iNum;

    static StaticClass()
    { }
}

it will throw compilation error:

"Static classes cannot contain protected members"

In fact, static members in non-static class cannot be overridden. 

public class BaseClass
{
    public static virtual void StaticMethod()
    { }
}

public class DerivedClass : BaseClass
{
    public override void StaticMethod()
    { }
}

Compilation error

"A static member cannot be marked as override, virtual, or abstract"

9. Lifetime

Static elements are in scope as soon as they referred in a program first-time and will remain in scope throughout the life of AppDomain.

This is an important concept to understand the scope of static elements, but I will discuss something more than that. Take a look at the example below:

C#
public class SampleClass
{
    static int _iCount = 0;

    static SampleClass()
    {
        Console.WriteLine("This is Static Ctor");
    }

    public void SetValue(int Count)
    {
        _iCount = Count;
    }

    public static void Print()
    {
        Console.WriteLine("The value of Count:{0}",
                            SampleClass._iCount);
    }
}

In the class above, we have a static field _iCount and static method Print(). In Main() program below, we are making a call to functions function1() and function2(). In both the functions, we are creating object on class SampleClass.

C#
class Program
{
    static void Main()
    {
        Console.WriteLine("First line in Main().");
        SampleClass.Print();
        function1();
        function2();
        SampleClass.Print();
        Console.WriteLine("Last line in Main().");
        Console.ReadLine();
    }

    public static void function1()
    {
        Console.WriteLine("First line in function1().");
        SampleClass objS2 = new SampleClass();
        objS2.SetValue(1);
        Console.WriteLine("Last line in function1().");
    }

    public static void function2()
    {
        Console.WriteLine("First line in function2().");
        SampleClass objS3 = new SampleClass();
        objS3.SetValue(2);
        Console.WriteLine("Last line in function2().");
    }
}

And finally the output of this program:

Image 5

Couple of interesting observations:

  • Second line of output is the call to Static constructor (see "This is static Ctor"). But if you refer to Main() function, we are neither creating the object nor instantiating. Even SampleClass is not declared as static. Yet, program makes a static constructor call. Remember in Point 4, we discussed that Static Constructor is called well before the instance constructor. The word "well before" is important as it suggests that as soon as static elements are accessed (with or without object creation), the constructor will initialize and then on, static members will be in scope but not as soon as program starts executing. Because the first line in the output (i.e. "First line in Main().") is the Main() function Console.writeline() statement and then the constructor of SampleClass gets called. To conclude, static elements are in scope as soon as they are referred by the program in any mean.
  • Also, There are objects ObjS2 and ObjS3 created in function1() and function2() respectively. Ideally their scope is within respective function body only. But when we print the value of the _iCount in Main(), printed value “2” set by function2() (i.e. objS3.SetValue(2)).

So take-a-way from last point, static element remains active till the last line of the program is executed. Our assumption is absolutely right with respect to this program. Reason being, the scope of our program is limited to one AppDomain. However if we introduce the different AppDomain, things will change. Let’s see another example.

Suppose we have one class library project 

namespace RemoteClassLibrary
{
    public class RemoteClass
    {
        static int _myID = 0;

        public RemoteClass()
        {
            Console.WriteLine("My ID is {0}", ++_myID);
        }
    }
}

And we have saved class library dll to local drive c:\app\. We have also create another program which uses reflection to execute this code

using System.Reflection;

namespace TestingProgram
{
    class Program
    {
        static void Main()
        {
            const string ClassLibraryPath = @"c:\app\RemoteClassLibrary.dll";

            //Load assembly in current App Domain
            Assembly Assembly1 = Assembly.LoadFrom(ClassLibraryPath);
            Assembly1.CreateInstance("RemoteClassLibrary.RemoteClass");

            //Load assembly in current App Domain
            Assembly Assembly2 = Assembly.LoadFrom(ClassLibraryPath);
            Assembly2.CreateInstance("RemoteClassLibrary.RemoteClass");

            Console.ReadKey();
        }
    }
}

And obvious output of this program is

Image 6

Please note that even thought that assembly is loaded, Static members still persists value or you can say only single copy of static class is created. Now let’s modify the main program to introduce multiple AppDomain which will load this assembly separately

class Program
{
    static void Main()
    {
        const string ClassLibrary = "RemoteClassLibrary.RemoteClass";
        const string ClassLibraryPath = @"c:\app\RemoteClassLibrary.dll";

        //Load class Library in AppDomain1
        AppDomain AppDomain1 = AppDomain.CreateDomain("AppDomain1");
        AppDomain1.CreateInstanceFrom(ClassLibraryPath, ClassLibrary);

        //Load class Library in AppDomain2
        AppDomain AppDomain2 = AppDomain.CreateDomain("AppDomain2");
        AppDomain2.CreateInstanceFrom(ClassLibraryPath, ClassLibrary);

        Console.ReadKey();
    }
}

Surprisingly the output,

Image 7

And so even though single program is executing but because of different AppDomain, the program is maintaining 2 copies of static member per AppDomain. In Sort, their scope is limited to AppDomain.

On Final note, we have discussed that the static elements are in scope as soon as they accessed first and limited to particular AppDomain.

Why Interface, structure and destructor cannot be static?

I’ve mentioned in point 1 that the Interface, structure and destructors cannot be static and I intentionally left the discussion without adding more details because we need to have enough base to before we can prove that. Now that we’ve visited some of key concepts around Static members, this is mature point to discuss in detail.

Interface setup a guidelines and expectations for the implementing classes of what their capabilities should be. If class is blueprint to the object then interface provides outlines/contract to the classes. To Justify, Interfaces describes objects capabilities but doesn’t provide the object representation. 

To make it clearer, let’s take an example

public interface IVehicle
{
    void Drive();
}

public class Car : IVehicle
{
    public void Drive()
    {
        Console.WriteLine("I am Driving Car");
    }
}

public class Bike : IVehicle
{
    public void Drive()
    {
        Console.WriteLine("I am Riding Bike");
    }
}

As you can see in the example above, Interface IVehicle provides contract to classes Car and Bike. And Car and Bike provides their native representation. IVehicle doesn’t have its own representation but can ask Car and Bike to provide own representation.

class Program
{
    static void Main()
    {
        IVehicle vehicle1 = new Car();
        vehicle1.Drive();
        //I am Driving Car

        IVehicle vehicle2 = new Bike();
        vehicle2.Drive();
        //I am Riding Bike

        Console.Read();
    }
}

Now for sake of understanding, Even if we assume that IVehicle is allowed to have static, it would not have object representation as static type cannot be instantiated (remember point 7) and IVehicle.Drive() will not have the representation. Thus semantically, static interface doesn’t make sense.

Coming to Structures, Structures stands separates from the class with respect to way they represented in the memory. Structures are value type and classes are reference type. Since we cannot have instance for static type, the result of static class and static struct would be same representation. It will cause unnecessary repetition and confusion.

Finally Destructors, they are intended for object memory cleanup (free up resources). Static types don’t have object representation and so we don’t need static destructors just like structures (value type) don’t have destructors.

Final Words

We have started with the simple concept of sharing the variables across all the objects of class but then we made a deep dive in each scenario that this simple concept represents and certainly leaves us by surprise. To give you a more precise example, it’s just like a client is proposing to implement a simple program but then over the period when you build, test, revisit and deliver, you will realize how much detail it requires to finish up the simple program. In our whole discussion, I have tried to demonstrate everything with an example to make it short, simple and yet effective. If you have anything which promises to change the article title from “9 Key Concept” to 10, 11, 12 or even more, let me know. I will be more than happy to add your suggestion, input and comments.

Happy learning!

Version History

Version 1.0 - Initial Article submitted

Version 1.1 - Following Changes

  • Added "Why Interface, structure and destructor cannot be static?"
  • Point 8 : Added Explanation for "Protected member of class" along with "Virtual" and "Override"
  • Point 9 : Elaborate scope of "Static element scope" to "AppDomain"

Other Article(s) by Author

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here