tags:

views:

499

answers:

4

I got an error today while trying to do some formatting to existing code. Originally, the code had the using directives declared outside the namespace:

using System.Collections.Generic;
namespace MyNamespace
{
    using IntPair = KeyValuePair<int, int>;
}

When I tried to insert the using directive inside the statement (to comply with StyleCop's rules), I got an error at the aliasing directive, and I had to fully qualify it:

namespace MyNamespace
{
    using System.Collections.Generic;
    //using IntPair = KeyValuePair<int, int>;   // Error!
    using IntPair = System.Collections.Generic.KeyValuePair<int, int>; // works
}

I wonder what difference there is between the two cases? Does the location of the (import-style) using directive matter?

+6  A: 

I used to think that it did not matter, but I always fully qualify using commands.

Edit: Checked the C# spec, section 9.4 says that:

The scope of a using-directive specifically does not include its peer using-directives. Thus, peer using-directives do not affect each other, and the order in which they are written is insignificant.

So if System.Collections.Generic and KeyValuePair are treated as peers then KeyValuePair is going to ignore System.Collections.Generic.

DavGarcia
+5  A: 

Yes, it does - to a small extent. There is an edge-case to do with scoping / local names, see Eric Lippert's blog.

For a concrete example (specific to alias usage):

using System;
using Foo = Bar;
public static class Bar {
    public  static void Test() { Console.WriteLine("outer"); }
}
namespace MyNamespace {
    //using Foo = Bar;

    public static class Bar {
        public static void Test() { Console.WriteLine("inner"); }
    }
    static class Program {
        static void Main() {
            Foo.Test();
        }
    }
}
Marc Gravell
+1  A: 

Yes it does, I have an working example to a similar question (Namespace collisions).

In essence the rules for name lookup are different if the using directive is global (outside the namespace) or inside the namespace when it takes higher precedence.

Pop Catalin
+1  A: 

This is purely informational, re one of the replies claiming it affects the time that the assembly is loaded; but in reality, assemblies are loaded the first time a method/type using them is JITted (or accessed via reflection, etc).

Here's an example showing it making no difference; with the using in either location, the output is the same: System.Core is loaded as Bar gets JITted:

pre-Bar
System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
pre-Max
Max: 5
post-Max
post-Bar

example (run at command line, not in debugger; ideally in release configuration):

using System;
//using System.Linq;
namespace Foo {
    using System.Linq;
    class Program {
        static Program() {
            AppDomain.CurrentDomain.AssemblyLoad += (s, a) => {
                Console.WriteLine(a.LoadedAssembly.FullName);
            };
        }
        static void Main() {            
            Console.WriteLine("pre-Bar");
            Bar();
            Console.WriteLine("post-Bar");
            Console.ReadLine();
        }
        static void Bar() {
            Console.WriteLine("pre-Max");
            int[] data = { 1, 2, 3, 4, 5 };
            Console.WriteLine("Max: " + Enumerable.Max(data));
            Console.WriteLine("post-Max");
        }
    }
}
Marc Gravell