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:
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.
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;
.
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
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With