Should 'using' directives be inside or outside the namespace?

249,619

Solution 1

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.

Solution 2

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.

Solution 3

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;
}

Solution 4

According to Hanselman - Using Directive and Assembly Loading... and other such articles there is technically no difference.

My preference is to put them outside of namespaces.

Solution 5

According the to StyleCop Documentation:

SA1200: UsingDirectivesMustBePlacedWithinNamespace

Cause A C# using directive is placed outside of a namespace element.

Rule Description A violation of this rule occurs when a using directive or a using-alias directive is placed outside of a namespace element, unless the file does not contain any namespace elements.

For example, the following code would result in two violations of this rule.

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

The following code, however, would not result in any violations of this rule:

namespace Microsoft.Sample
{
    using System;
    using Guid = System.Guid;

    public class Program
    {
    }
}

This code will compile cleanly, without any compiler errors. However, it is unclear which version of the Guid type is being allocated. If the using directive is moved inside of the namespace, as shown below, a compiler error will occur:

namespace Microsoft.Sample
{
    using Guid = System.Guid;
    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

The code fails on the following compiler error, found on the line containing Guid g = new Guid("hello");

CS0576: Namespace 'Microsoft.Sample' contains a definition conflicting with alias 'Guid'

The code creates an alias to the System.Guid type called Guid, and also creates its own type called Guid with a matching constructor interface. Later, the code creates an instance of the type Guid. To create this instance, the compiler must choose between the two different definitions of Guid. When the using-alias directive is placed outside of the namespace element, the compiler will choose the local definition of Guid defined within the local namespace, and completely ignore the using-alias directive defined outside of the namespace. This, unfortunately, is not obvious when reading the code.

When the using-alias directive is positioned within the namespace, however, the compiler has to choose between two different, conflicting Guid types both defined within the same namespace. Both of these types provide a matching constructor. The compiler is unable to make a decision, so it flags the compiler error.

Placing the using-alias directive outside of the namespace is a bad practice because it can lead to confusion in situations such as this, where it is not obvious which version of the type is actually being used. This can potentially lead to a bug which might be difficult to diagnose.

Placing using-alias directives within the namespace element eliminates this as a source of bugs.

  1. Multiple Namespaces

Placing multiple namespace elements within a single file is generally a bad idea, but if and when this is done, it is a good idea to place all using directives within each of the namespace elements, rather than globally at the top of the file. This will scope the namespaces tightly, and will also help to avoid the kind of behavior described above.

It is important to note that when code has been written with using directives placed outside of the namespace, care should be taken when moving these directives within the namespace, to ensure that this is not changing the semantics of the code. As explained above, placing using-alias directives within the namespace element allows the compiler to choose between conflicting types in ways that will not happen when the directives are placed outside of the namespace.

How to Fix Violations To fix a violation of this rule, move all using directives and using-alias directives within the namespace element.

Share:
249,619
benPearce
Author by

benPearce

Developer working mostly with a Microsoft stack

Updated on January 29, 2022

Comments

  • benPearce
    benPearce over 2 years

    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?

    • gius
      gius over 15 years
      Sometimes it makes difference where you put usings: stackoverflow.com/questions/292535/linq-to-sql-designer-bug
    • Charlie
      Charlie over 14 years
      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.
    • benPearce
      benPearce over 10 years
      @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.
    • Jeppe Stig Nielsen
      Jeppe Stig Nielsen about 7 years
      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(); } }.
    • user1451111
      user1451111 almost 6 years
      If this was not mentioned already by anyone, actually Microsoft too recommends putting using statements inside the namespace declarations, in their internal coding guidlines
    • Gabriel
      Gabriel over 2 years
      Putting them outside the namespace assists in detecting naming conflicts sooner rather than later, if used as a convention in a team, as it would be consistently at the same level as all other using directives.
  • benPearce
    benPearce over 14 years
    @Jared - as I noted in my answer, my prefered workaround / solution is to only ever have one class per file. I think that this is a fairly common convention.
  • Task
    Task about 14 years
    Indeed, it's also a StyleCop rule! SA1402: A C# document may only contain a single class at the root level unless all of the classes are partial and are of the same type. Showcasing one rule by breaking another just drips with wrong sauce.
  • johnny
    johnny over 12 years
    @Chris M: uh... the link posted in the answer indicates there's no benefit to in vs. out, actually showing an example that falsifies the claim made in the link you posted...
  • Chris McKee
    Chris McKee over 12 years
    Aye I didn't fully read the thread but bought in when the MVPs said it was right. A guy disproves it, explains it and shows his code further down... "The IL that the C# compiler generates is the same in either case. In fact the C# compiler generates precisely nothing corresponding to each using directive. Using directives are purely a C#ism, and they have no meaning to .NET itself. (Not true for using statements but those are something quite different.)" groups.google.com/group/wpf-disciples/msg/781738deb0a15c46
  • ANeves
    ANeves over 11 years
    Please include a summary of the link. When the link is broken (because it will happen, given enough time), suddenly an answer with 32 upvotes is only worth My style is to put them outside the namespaces. - barely an answer at all.
  • Jowen
    Jowen over 10 years
    namespaces provide a logical separation, not a physical (file) one.
  • O. R. Mapper
    O. R. Mapper over 10 years
    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.
  • Mark Cidade
    Mark Cidade over 10 years
    yeah I know. we established that in this question's accepted answer five years ago.
  • Aisah Hamzah
    Aisah Hamzah over 9 years
    No, actually that is a bad idea. You should not base the location between locally scoped and globally scoped of using directives on the fact that they are newly added or not. Instead, it is good practice to alphabetize them, except for BCL references, which should go on top.
  • nawfal
    nawfal almost 9 years
    Upvoted for being the first answer to actually cover it from the StyleCop perspective. Personally I like the visual feel of usings outside the namespace. Inner usings looks so ugly to me. :)
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen about 8 years
    Your class needs a name (identifier). You cannot have a using directive inside a class as you indicate. It must be on a namespace level, for example outside the outermost namespace, or just inside the innermost namespace (but not inside a class/interface/etc.).
  • Neo
    Neo about 8 years
    @JeppeStigNielsen Thanks. I misplaced the using directives mistakenly. I've edited it to how I intended it to be. Thanks for pointing out. The reasoning is still the same, though.
  • Jim Balter
    Jim Balter about 8 years
    The claim here is simply wrong ... there is a technical difference and your own citation says so ... in fact, that's what it's all about. Please delete this mistaken answer ... there are far better, and accurate, ones.
  • Jim Balter
    Jim Balter about 8 years
    Finally a good answer to the question. And benPearce's comment is irrelevant ... this has nothing to do with the number of classes in the file.
  • Keith Robertson
    Keith Robertson over 7 years
    It is true that you "may omit the outer namespace," but it doesn't mean you should. To me, this is another argument as to why using directives (other than aliases as in @Neo's answer) should go outside the namespace, to force fully-qualified namespace names.
  • Alexander
    Alexander over 3 years
    Good point! I bumped into the related issue working with RazorGenerator. Unfortunately, seems like it does not understand 'global::' and converts it to `using global;' :( It's a pity I cannot select if 'using' needs to be generated inside or outside of 'namespace'...
  • Eric Lippert
    Eric Lippert about 3 years
    @jwdonahue: When I was invited to join the C# feature design team I had been a professional compiler developer and language designer for almost a decade and I was by far the most junior person in the room. The C# design team will certainly take great ideas that come from interns; the notion that there is a dearth of experience in designing, evaluating, specifying and implementing language features on the C# design team is not factual.
  • Eric Lippert
    Eric Lippert about 3 years
    Similarly, this answer opens with the bizarre and utterly contrary to fact supposition that the authors of the frameworks design guidelines are just making a list of their preferences. Nothing could be further from the truth. We vigorously debated those guidelines in a room full of experts and stakeholders; they were the product of careful consideration of the needs of professional developers.
  • jwdonahue
    jwdonahue about 3 years
    @EricLippert, in hind-sight, it was a silly thought I shouldn't have voiced. Apologies.
  • Paul Evans
    Paul Evans about 3 years
    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.
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen about 3 years
    @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.
  • andrewf
    andrewf almost 3 years
    I think this is an otherwise solid answer which is diminished (and probably downvoted because of) the first and last paragraphs. I suggest just removing the first and last paragraphs.
  • Martin
    Martin almost 3 years
    OP has stated "there is technically no difference" in their answer and they are correct - from a technical perspective there is no difference. Claiming that this is a mistaken answer is plain wrong
  • Yrth
    Yrth over 2 years
    @andrewf Nice to see a response that offers some solid ideas to improve the post. My thanks. Although I don't quite see the issue with the last paragraph...
  • surfmuggle
    surfmuggle almost 2 years
    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?
  • T. Sar
    T. Sar almost 2 years
    @surfmuggle I believe that your link refers specifically to console apps without a main method, if I'm not mistaken.
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen almost 2 years
    I think this is explained by the search order I give in my answer above. In file3.cs you have to say Foo.Foo, as you say. The using directive there is useless. However, in file2.cs, you have no access to the namespace. Like if you say Foo.DeeperNamespace.SomeClass in Main method, it will search only inside Foo class, not inside the Foo namespace. So you will need global::Foo.DeeperNamespace there. In any case, all guides advise against using the same name for a namespace and a type.