Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you explain this edge case involving the C# 'using' keyword with namespace declarations and members?

Tags:

c#

Consider the following short code snippet.

namespace B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}

namespace A.B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}

Get familiar with example #1 first.

using B;

namespace A.C
{
    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Foo().Text);
        }
    }
}

Now consider example #2.

namespace A.C
{
    using B; // Notice the placement here.

    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Foo().Text);
        }
    }
}

There is nothing terribly peculiar about example #1. However, things get interesting with example #2. It is imperative that you pay close attention to all identifiers used in the examples. As a fun exercise try to guess what happens without plugging this into the compiler. I will not reveal the answer here because 1) it is easy enough to try yourself and 2) I do not want to ruin the fun.

Will the program:

  • not compile
  • display B.Foo
  • display A.B.Foo

The question...Where in the C# specification is this behavior described?

I did take a look at section 3.7 in the C# 4.0 specification and especially bullet #2, but I do not think that explains the behavior. If anything it almost makes me think the compiler is behaving contradictory to the specification.

like image 962
Brian Gideon Avatar asked Jul 01 '10 14:07

Brian Gideon


3 Answers

The first example prints "B.Foo", the second example prints "A.B.Foo". This is because in the second example the using B; directive is enclosed inside the A.C namespace.

Why does it use A.B rather than B?

Because namespace lookups follow the same rules as type name qualification lookups. Section 3.8 of the C# spec.

Basically, when the using directive is processed by the compiler , the symbol B is looked for in the A.C namespace. Not finding it, it's looked for in the A namespace. Because it's found there as a sub-namespace of A, it selects that namespace and doesn't go to the global namespace to find the B namespace.

Edit:
As @P.Brian.Mackey suggests, you can get to the B namespace with using global::B;.

like image 76
Randolpho Avatar answered Oct 11 '22 17:10

Randolpho


I didnt read the C# specifications, but I can tell you what's happening simply by deduction. When you put using B inside of the A.C namespace you are no longer in global scope, you are in the scope of the surrounding namespace. First the app will try to resolve in A.C, then in A.

The easiest fix is simply to change the inside using statement to:

using global::B;

But, you can further see this occuring by adding

namespace A.C.B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}

Note that you now resolve to A.C.B

like image 30
P.Brian.Mackey Avatar answered Oct 11 '22 15:10

P.Brian.Mackey


The other answers are correct, but one additional note. It helps to remember that

namespace A.C 
{
    using B;

actually is just a short way of writing

namespace A
{
    namespace C
    {
        using B;

Which might make it a bit more clear what is going on here. When resolving B we check A for B before we check the container of A.

If you're interested in ways that namespace lookups can go horribly wrong, see my series of articles about that:

http://blogs.msdn.com/b/ericlippert/archive/tags/namespaces/

like image 24
Eric Lippert Avatar answered Oct 11 '22 17:10

Eric Lippert