Fabulous Adventures In Coding

Eric Lippert's Blog

Inside or Outside?

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
  • if you choose to put using directives inside your namespaces 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.

Published Monday, June 25, 2007 7:31 AM by Eric Lippert
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Stuart Ballard said:

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.

June 25, 2007 3:06 PM
 

Henry Boehlert said:

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.

June 26, 2007 5:49 AM
 

Stefan Wenig said:

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

June 27, 2007 12:23 PM
 

Ricky said:

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

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

May 26, 2008 11:28 PM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker