Categories
.net c# code-organization namespaces stylecop

Should ‘using’ directives be inside or outside the namespace?

2320

I have been running StyleCop over some C# code, and it keeps reporting that my using directives should be inside the namespace.

Is there a technical reason for putting the using directives inside instead of outside the namespace?

6

  • 6

    Sometimes it makes difference where you put usings: stackoverflow.com/questions/292535/linq-to-sql-designer-bug

    – gius

    Dec 12, 2008 at 18:15

  • 89

    Just for reference, there are implications beyond just the question of multiple classes per file, so if you’re new to this question, please keep reading.

    – Charlie

    Jan 22, 2010 at 17:23

  • 4

    @user-12506 – this does not work very well in a medium to large development team where some level of code consistency is required. And as noted previously, if you don’t understand the different layouts you may find edge cases that don’t work as you expect.

    – benPearce

    Feb 3, 2014 at 22:28


  • 55

    Terminology: Those are not using statements; they are using directives. A using statement, on the other hand, is a language structure that occurs along with other statements inside a method body etc. As an example, using (var e = s.GetEnumerator()) { /* ... */ } is a statement that is loosely the same as var e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }.

    Apr 11, 2017 at 21:30

  • 2

    If this was not mentioned already by anyone, actually Microsoft too recommends putting using statements inside the namespace declarations, in their internal coding guidlines

    Jul 27, 2018 at 2:15

2330

There is actually a (subtle) difference between the two. Imagine you have the following code in File1.cs:

// File1.cs
using System;
namespace Outer.Inner
{
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Now imagine that someone adds another file (File2.cs) to the project that looks like this:

// File2.cs
namespace Outer
{
    class Math
    {
    }
}

The compiler searches Outer before looking at those using directives outside the namespace, so it finds Outer.Math instead of System.Math. Unfortunately (or perhaps fortunately?), Outer.Math has no PI member, so File1 is now broken.

This changes if you put the using inside your namespace declaration, as follows:

// File1b.cs
namespace Outer.Inner
{
    using System;
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Now the compiler searches System before searching Outer, finds System.Math, and all is well.

Some would argue that Math might be a bad name for a user-defined class, since there’s already one in System; the point here is just that there is a difference, and it affects the maintainability of your code.

It’s also interesting to note what happens if Foo is in namespace Outer, rather than Outer.Inner. In that case, adding Outer.Math in File2 breaks File1 regardless of where the using goes. This implies that the compiler searches the innermost enclosing namespace before it looks at any using directive.

2

  • Fundamentals – program-structure states for c#-9.0 .net-6.0 that using directives must come first in the file. Does anyone know what this means for the example above?

    Jun 21 at 20:24

  • @surfmuggle I believe that your link refers specifically to console apps without a main method, if I’m not mistaken.

    – T. Sar

    Jun 23 at 16:30

538

This thread already has some great answers, but I feel I can bring a little more detail with this additional answer.

First, remember that a namespace declaration with periods, like:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

is entirely equivalent to:

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

If you wanted to, you could put using directives on all of these levels. (Of course, we want to have usings in only one place, but it would be legal according to the language.)

The rule for resolving which type is implied, can be loosely stated like this: First search the inner-most “scope” for a match, if nothing is found there go out one level to the next scope and search there, and so on, until a match is found. If at some level more than one match is found, if one of the types are from the current assembly, pick that one and issue a compiler warning. Otherwise, give up (compile-time error).

Now, let’s be explicit about what this means in a concrete example with the two major conventions.

(1) With usings outside:

using System;
using System.Collections.Generic;
using System.Linq;
//using MyCorp.TheProduct;  <-- uncommenting this would change nothing
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    class C
    {
        Ambiguous a;
    }
}

In the above case, to find out what type Ambiguous is, the search goes in this order:

  1. Nested types inside C (including inherited nested types)
  2. Types in the current namespace MyCorp.TheProduct.SomeModule.Utilities
  3. Types in namespace MyCorp.TheProduct.SomeModule
  4. Types in MyCorp.TheProduct
  5. Types in MyCorp
  6. Types in the null namespace (the global namespace)
  7. Types in System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, and ThirdParty

The other convention:

(2) With usings inside:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using MyCorp.TheProduct;                           // MyCorp can be left out; this using is NOT redundant
    using MyCorp.TheProduct.OtherModule;               // MyCorp.TheProduct can be left out
    using MyCorp.TheProduct.OtherModule.Integration;   // MyCorp.TheProduct can be left out
    using ThirdParty;

    class C
    {
        Ambiguous a;
    }
}

Now, search for the type Ambiguous goes in this order:

  1. Nested types inside C (including inherited nested types)
  2. Types in the current namespace MyCorp.TheProduct.SomeModule.Utilities
  3. Types in System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, and ThirdParty
  4. Types in namespace MyCorp.TheProduct.SomeModule
  5. Types in MyCorp
  6. Types in the null namespace (the global namespace)

(Note that MyCorp.TheProduct was a part of “3.” and was therefore not needed between “4.” and “5.”.)

Concluding remarks

No matter if you put the usings inside or outside the namespace declaration, there’s always the possibility that someone later adds a new type with identical name to one of the namespaces which have higher priority.

Also, if a nested namespace has the same name as a type, it can cause problems.

It is always dangerous to move the usings from one location to another because the search hierarchy changes, and another type may be found. Therefore, choose one convention and stick to it, so that you won’t have to ever move usings.

Visual Studio’s templates, by default, put the usings outside of the namespace (for example if you make VS generate a new class in a new file).

One (tiny) advantage of having usings outside is that you can then utilize the using directives for a global attribute, for example [assembly: ComVisible(false)] instead of [assembly: System.Runtime.InteropServices.ComVisible(false)].


Update about file-scoped namespace declarations

Since C# 10.0 (from 2021), you can avoid indentation and use either (convention 1, usings outside):

using System;
using System.Collections.Generic;
using System.Linq;
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities;

class C
{
    Ambiguous a;
}

or (convention 2, usings inside):

namespace MyCorp.TheProduct.SomeModule.Utilities;

using System;
using System.Collections.Generic;
using System.Linq;
using MyCorp.TheProduct;
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

class C
{
    Ambiguous a;
}

But the same considerations as before apply.

2

  • 2

    Just had a case where a class library I inherited had some classes in the global/null namespace. One of the class names was the same as a class name inside a namespace I was using. The ‘using’s were outside the namespace definition. I couldn’t figure out why it would always pick up the definition of the global class. By chance, put the namespace outside – and it picked up the class I needed. Your answer explains why. With the namespace outside, null/globals get picked up last. To me, this is the proper/expected behavior.

    Mar 23, 2021 at 6:02


  • 1

    @PaulEvans Your case is also an example why one should never put anything in the global namespace, especially not anything public. The library you used violated that.

    Mar 23, 2021 at 23:40

209

Putting it inside the namespaces makes the declarations local to that namespace for the file (in case you have multiple namespaces in the file) but if you only have one namespace per file then it doesn’t make much of a difference whether they go outside or inside the namespace.

using ThisNamespace.IsImported.InAllNamespaces.Here;

namespace Namespace1
{ 
   using ThisNamespace.IsImported.InNamespace1.AndNamespace2;

   namespace Namespace2
   { 
      using ThisNamespace.IsImported.InJustNamespace2;
   }       
}

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

3

  • 1

    namespaces provide a logical separation, not a physical (file) one.

    – Jowen

    Sep 26, 2013 at 11:08

  • 11

    It’s not quite true that there is no difference; using directives within namespace blocks can refer to relative namespaces based on the enclosing namespace block.

    Feb 9, 2014 at 10:07

  • 73

    yeah I know. we established that in this question’s accepted answer five years ago.

    Feb 10, 2014 at 21:58