top of page

Lesson 12 : Namespaces And Statics

We finally cover the rest of the stuff we've seen populate our code files since the very first Hello World program.

Lesson Summary:

Namespaces

A namespace is a region of code with a specific name. When you define a namespace, everything within it exists under the context of that namespace. For example, see these two namespaces:

    namespace FirstNamespace

    {

         class MyClass

         {

              void DoStuff() { Console.WriteLine("I am in FirstNamespace"); }

         }

    }

    namespace OtherNamespace

    {

         class MyClass

         {

              void DoStuff() { Console.WriteLine("I am in OtherNamespace "); }

         }

    }

In this example there are two namespaces, and each has a class named MyClass. Normally, you cannot have two classes with the same name in a single namespace (as would be the case with variables under the same scope). However, objects such as classes can have the same names as long as they are in different namespaces. In the example above, the full name for the first class is FirstNamespace.MyClass, and the full name for the second class is OtherNamespace.MyClass. This is a similar idea to how two different people can share the name "John" but they can be differentiated by their last names, say John Smith and John Potter.

To see the above in action, we can do the following in our Main function:

   FirstNamespace.MyClass class1 = new FirstNamespace.MyClass();

   OtherNamespace.MyClass class2 = new OtherNamespace.MyClass();

   class1.DoStuff();

   class2.DoStuff();

If you run the above code, you will see that, despite having the same name (excluding namespace), both classes behave differently when calling DoStuff, since they are different due to being in different namespaces.

Note that you do not need to specify a namespace while you are within that namespace:

    namespace FirstNamespace

    {

         class MyClass

         {

              void DoStuff() { Console.WriteLine("I am in FirstNamespace"); }

         }

         class OtherClass

         {

             void DoStuff()

             {

                MyClass thing = new MyClass(); // Does not need to specify FirstNamespace

             }

         }

    }

In the example above, we see that it's not necessary to fully qualify the class MyClass with FirstNamespace.MyClass because we are already within FirstNamespace. Thus, that namespace is assumed. However, it's still acceptable to write out FirstNamespace.MyClass, and it could be helpful in cases of ambiguity.

Usings

As it turns out, there are two totally different uses for the keyword "using"  in C#. In this lesson I will cover the one that relates to the statements often seen at the top of a code file, such as "using System;"

A using statement is an alternative to specifying a namespace directly. When writing a using statement followed by a namespace (such as System or System.Collections.Generic), all objects within that namespace are implicitly identified without needing to specify their namespace specifically. For example, see this full code file:

   using System;

   namespace ConsoleApplication2
   {
     class Program
     {
         static void Main(string[] args)
         {

             Console.Out.WriteLine("Hello World");
         }
      }
   } 

Note the "using System" at the top. Also note (when writing the code in Visual Studio) that Console is colored blue, and if you hover the mouse over it, it will be identified as "System.Console". It turns out, Console belongs to the namespace System. If we remove "using System;", Console will no longer be blue and we will get an error:

   namespace ConsoleApplication2
   {
     class Program
     {
         static void Main(string[] args)
         {

             Console.Out.WriteLine("Hello World"); // Compiler complains that Console does not exist
         }
      }
   }

This can be fixed by adding the using, or by specifying the namespace explicitly as described in the previous section:

    System.Console.WriteLine("Hello World");

You can also specify the namespace explicitly even while having the using, which could be necessary in case of namespace conflicts.

Conflicts:

Note that if you have two names that are the same accross different namespaces and you include both namespaces thru usings, there will be ambiguity. For example:

    namespace FirstNamespace

    {

         class MyClass {}

    }

    namespace OtherNamespace

    {

         class MyClass {}

    }

   using FirstNamespace;

   using OtherNamespace;

   namespace MyProgram

   {

      class Program

      {

          static void Main(string[] args)

          {

               MyClass class = new MyClass(); // Compiler error; ambiguity about which MyClass this references

          }

      }

   }

In this example, you can see that we specify MyClass without the explicit namespace identifier (ie without doing FirstNamespace.MyClass). Instead, we include both usings, for both possible namespaces. The compiler gets confused here because it doesn't know which of the two MyClass corresponds to, as it could be either. Note that this won't occur if you only specify one of the two usings. You can resolve this issue either by removing one of the namespaces or by qualifying the MyClass with the correct namespace, such as FirstNamespace.MyClass or OtherNamespace.MyClass.

Statics

The static keyword is more intricate than the sum of its parts, but for the sake of sanity, I will just describe here the aspects of static that are necessary to know by this point in the course. In the future I'll cover the topic in more depth.

When used with a member of a class, such as a method, a field or a property, the keyword static specifies that only a single instance of that member exists, globally, and that it is not tied to instances of a class. For example, see the distinction here between these two fields, only one of which is static:

   class Car

   {

      private int id;

      public static int totalCarsMade = 0;

      public Car(int newId)

      {

         this.id = newId;

         totalCarsMade++;

      }

   }

   static void Main(string[] args)

   {

       Car car1 = new Car(1);

       Car car2 = new Car(1);

   }

When we create a Car instance here, we set the id and "totalCarsMade" fields in the constructor. For the first car, its id field will be set to 1 and its totalCarsMade field will be incremented to 1 (because it starts at 0). When we create the second Car instance, the id is also set to 1, but totalCarsMade is incremented to 2, not to 1. That is because totalCarsMade is static, and it is thus a global value shared among all instances of Car. Furthermore, it also exists even when there is no instance of Car. Since I marked it public, I could do the following to use this field without first creating an instance of Car:

   Console.WriteLine("Total cars made: " + Car.totalCarsMade);

Contrast this with a non-static field, such as id, whose value is unique to each instance of Car.

You can also make methods static. These also do not require an instance in order to be called. We have seen a method like this: Console.WriteLine. As you've seen many times already, we are able to call Console.WriteLine without instantiating Console by using "new Console" (as it turns out, Console is a special kind of class called a static class, which means it can only have static members). This is handy for creating methods like WriteLine which you want to be able to simply call from anywhere without requiring an instance of an object.

Limitations of statics

Statics have certain limitations which make quite a bit of sense when you consider them carefully:

  • Static methods within a class can only reference other static members of that class

    • However, you can create an instance of a class within a static method, and call a non-static method from there.; it will correspond to the instance created in that method.

  • Classes cannot use the "this" keyword to refer to a static member

  • You cannot call static methods using the dot (.) operator of an instance of the class. You must do Class.Method.

On the other hand, the following rules also apply:

  • Non-static class methods can reference static members such as methods, fields and properties.

  • Static members can be protected using keywords like "private" and "public" just like any other class members.

Practice: Honk Counter

Honking is a thing that happens, but it is also a thing that must be counted.

bottom of page