Inside or Outside?

Inside or Outside?

  • Comments 4

Here's a question I was asked recently which I got wrong. This is why I always encourage Microsofties to ask the entire C#/VB/whatever-interest-group their question, rather than directing it to me specifically.

The question was which is "better"? (The following code snippets are not nested inside any namespace.)

using Blah;
namespace Foo {
  // etc
}

or

namespace Foo {
  using Blah;
  // etc
}

I don't know how to answer the question "which is better?" because I do not know the intended purpose of the code. I therefore tried to think of ways that these could be different, and answer the question "how do these differ?"

My answer was that if there is only one namespace in the file, it hardly matters. If there are two or more namespaces in the file, then put the directives you want shared amongst them at the top of the file, and the ones you do not want shared inside each the namespace. I further noted that having multiple top-level namespaces in the same file is a little weird, so maybe don't even go there and make it a moot point.

My first statement was not right. There is a way that these could be different that I forgot about. The first version is equivalent to

using global::Blah;
namespace Foo {
  // etc
}

The second version is equivalent to

namespace Foo {
  using global::Blah;
  // etc
}

unless Foo contains a namespace called Blah. In that case, it is equivalent to

namespace Foo {
  using global::Foo.Blah;
  // etc
}

So there are at least two ways that things can get broken here. First, moving a not-fully-qualified directive from outside to inside (or vice versa) may cause a semantic change in the program. And second, if there is a not-fully-qualified directive inside the namespace which refers to a top-level namespace then adding a child namespace that collides with that name can introduce a semantic change in the program.

Therefore my advice is now:

  • have only one top-level namespace per file
  • do not have multiple namespaces at different points in the hierarchy with the same name; that's just confusing
  • if you choose to put using directives inside your namespaces and you are worried that you might have multiple namespaces at different points in the hierarchy with the same name, then fully qualify them with the global alias qualifier

If you take this advice then it really does not matter whether the directives go inside the namespace or outside; either way you will not accidentally break yourself by introducing a name collision.

  • There's another difference between the two that I've found to be useful. My company's product is an ASP.NET application and has an important class called Panel. But System.Web.UI.WebControls also has a class called Panel (which we never use). To avoid having to type "NR.CMS.Core.Panel" every time we want to use one of our panels, we structure our using declarations like this:

    using System.Web.UI.WebControls;

    namespace NR.CMS.Whatever {

     using NR.CMS.Core;

     ...

    }

    Yes, we could do "using Panel = NR.CMS.Core.Panel;" to solve the same problem, but that solves one specific case. Putting our own usings inside the namespace solves the general case of the problem - that we usually mean a class in our own namespaces if such a class exists.

  • IMHO CodeDOM stipulates the latter by providing only CodeNamespace.Imports to add CodeNamespaceImport instances.

    So every piece of code generated thru CodeDOM will use inline imports. However, these will also be global and thus will not conflict with your advice.

  • I pointed out another difference, but it seems your blog engine ate it. Here it is again:

    This does not work:

    using System;

    using System.Collections.Generic;

    using Int32List = List<Int32>; // won't compile

    you either need to write the last line fully qualified:

    using Int32List = System.Collections.Generic<System.Int32>;

    or you can split the usings:

    using System;

    using System.Collections.Generic;

    namespace MyNS {

     using Int32List = List<Int32>;

  • Oh well ... "StyleCop" is suggesting to put inside.

    Dont know the reason yet except limiting the scope of namespaces.

Page 1 of 1 (4 items)