Using Static Members

The properties and methods of a class can be either instance members or static members. Instance members are associated with instances of a type, while static members are considered to be part of the class. You access a static member through the name of the class in which it is declared. For example, suppose you have a class named Button and have instantiated objects of that class named btnUpdate and btnDelete. Suppose as well that the Button class has a static method SomeMethod( ). To access the static method you write:

Button.SomeMethod( );

rather than writing:

btnUpdate.SomeMethod( );

In C# it is not legal to access a static method or member variable through an instance, and trying to do so will generate a compiler error (C++ programmers, take note).

Some languages distinguish between class methods and other (global) methods that are available outside the context of any class. In C# there are no global methods, only class methods, but you can achieve an analogous result by defining static methods within your class.

Static methods act more or less like global methods, in that you can invoke them without actually having an instance of the object at hand. The advantage of static methods over global, however, is that the name is scoped to the class in which it occurs, and thus you do not clutter up the global namespace with myriad function names. This can help manage highly complex programs, and the name of the class acts very much like a namespace for the static methods within it.

Tip

Resist the temptation to create a single class in your program in which you stash all your miscellaneous methods. It is possible but not desirable and undermines the encapsulation of an object-oriented design.

Invoking Static Methods

The Main( ) method is static. Static methods are said to operate on the class, rather than on an instance of the class. They do not have a this reference, as there is no instance to point to.

Static methods cannot directly access nonstatic members. For Main( ) to call a nonstatic method, it must instantiate an object. Consider Example 4-2, reproduced here for your convenience.

using System;

public class MyClass
{
   public void SomeMethod(int firstParam, float secondParam)
   {
      Console.WriteLine(
         "Here are the parameters received: {0}, {1}",
         firstParam, secondParam);
   }

}

public class Tester
{
   static void Main( )
   {
      int howManyPeople = 5;
      float pi = 3.14f;
      MyClass mc = new MyClass( );
      mc.SomeMethod(howManyPeople, pi);
   }

}

SomeMethod( ) is a nonstatic method of MyClass. For Main( ) to access this method, it must first instantiate an object of type MyClass and then invoke the method through that object.

Using Static Constructors

If your class declares a static constructor, you will be guaranteed that the static constructor will run before any instance of your class is created.

Tip

You are not able to control exactly when a static constructor will run, but you do know that it will be after the start of your program and before the first instance is created. Because of this you cannot assume (or determine) whether an instance is being created.

For example, you might add the following static constructor to Time:

static Time( )
{
     Name = "Time";
}

Notice that there is no access modifier (e.g., public) before the static constructor. Access modifiers are not allowed on static constructors. In addition, because this is a static member method, you cannot access nonstatic member variables, and so Name must be declared a static member variable:

private static string Name;

The final change is to add a line to DisplayCurrentTime( ), as in the following:

public void DisplayCurrentTime( )
{
   System.Console.WriteLine("Name: {0}", Name);
   System.Console.WriteLine("{0}/{1}/{2} {3}:{4}:{5}", 
      Month, Date, Year, Hour, Minute, Second);
}

When all these changes are made, the output is:

Name: Time
11/27/2005 7:52:54
Name: Time
11/18/2005 11:45:30

(Your output will vary depending on the date and time you run this code.)

Although this code works, it is not necessary to create a static constructor to accomplish this goal. You could, instead, use an initializer:

private static string Name = "Time";

which accomplishes the same thing. Static constructors are useful, however, for set-up work that cannot be accomplished with an initializer and that needs to be done only once.

For example, assume you have an unmanaged bit of code in a legacy dll. You want to provide a class wrapper for this code. You can call load library in your static constructor and initialize the jump table in the static constructor. Handling legacy code and interoperating with unmanaged code is discussed in Chapter 22.

Using Private Constructors

In C# there are no global methods or constants. You might find yourself creating small utility classes that exist only to hold static members. Setting aside whether this is a good design or not, if you create such a class you will not want any instances created. You can prevent any instances from being created by creating a default constructor (one with no parameters), which does nothing, and which is marked private. With no public constructors, it will not be possible to create an instance of your class.[8]

Using Static Fields

A common use of static member variables is to keep track of the number of instances that currently exist for your class. Example 4-5 illustrates.

Example 4-5. Using static fields for instance counting

using System;

public class Cat
{

     public Cat( )
     {
          instances++;  
     }

     public static void HowManyCats( )
     {
          Console.WriteLine("{0} cats adopted",
                instances);
     }
     private static int instances = 0;
}

public class Tester
{
     static void Main( )
     {
           Cat.HowManyCats( );
           Cat frisky = new Cat( );
           Cat.HowManyCats( );
           Cat whiskers = new Cat( );
           Cat.HowManyCats( );

     }

}

Output:
0 cats adopted
1 cats adopted
2 cats adopted

The Cat class has been stripped to its absolute essentials. A static member variable called instances is created and initialized to zero. Note that the static member is considered part of the class, not a member of an instance, and so it cannot be initialized by the compiler on creation of an instance. Thus, an explicit initializer is required for static member variables. When additional instances of Cats are created (in a constructor), the count is incremented.



[8] You can create a public static method that calls the constructor and creates an instance of your class. Typically you might use this idiom to ensure that only one instance of your class ever exists. This is known as the Singleton design pattern, as described in the seminal work Design Patterns by Gamma, et al. (Addison Wesley, 1995).

Get Programming C#, Second Edition now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.