A using clause inside a namespace is different to a using clause outside a namespace

For some reason I always forget the difference between using a using clause inside a namespace as opposed to outside. Occasionally I come across other people’s code where they’ve obviously explicitly copied their using clauses inside their namespace, being that by default creating a new C# file will place the default using clauses at the top of the file (outside the namespace).

So what’s the difference ?

If we have a class sitting in a namespace such as MyNamespace.MyClasses (with using System; outside the namespace) such as

using System;

namespace MyNamespace.MyClasses
{
   class MyClass
   {
      void MyMethod()
      {
         String s = String.Empty;
         // do something
      }
   }
}

It’s happily using the System.String object, but then along comes a new developer on the project who creates a String class specific to the project.

So the new class is added to the MyNamespace namespace in the following way

namespace MyNamespace
{
   class String
   {
   }
}

At this point our previous code will fail with a ‘MyNamespace.String’ does not contain a definition for ‘Empty’. This is because when the compiler searches for the String class it starts in the MyNamespace.MyClasses namespace then the MyNamespace namespace and then finally the using clauses outside of the namespace. So in this instance it finds a matching String class in the namespace MyNamespace and unless the String is fully qualified (i.e. System.String s = System.String.Empty; will try to use this. Obviously this is the wrong String class.

If we move the using System; inside the namespace of MyClass, such as

namespace MyNamespace.MyClasses
{
   using System;
   
   class MyClass
   {
      void MyMethod()
      {
         String s = String.Empty;
      }
   }
}

In this instance the compiler searches the MyNamespace.MyClasses namespace and then the using clauses within that namespace and so can resolve the String.Empty const and the newly added String class can still be implemented without being mistakenly used.