C# allows the definition of nested namespaces:
namespace A.B
{
class Class1 {}
}
Per the C# 6.0 draft specification, this is semantically equivalent to:
namespace A
{
namespace B
{
class Class1 {}
}
}
This has consequences that may be surprising if there are types with the same names in the parent and child namespaces.
In the following code, which Class1
does X.Class2
use?
namespace A
{
class Class1
{
public void DoA() {}
}
}
namespace A.B
{
class Class1
{
public void DoB() {}
}
}
namespace X
{
using A.B;
class Class2
{
public void DoSomething()
{
= new ();
Class1 x
// The using directive brings A.B.Class1 into scope, as expected.
.DoB();
x}
}
}
So far, so good. But what if Class2
is in namespace A.C
? Remember that this is equivalent to a C
namespace nested in the A
namespace.
namespace A
{
class Class1
{
public void DoA() {}
}
}
namespace A.B
{
class Class1
{
public void DoB() {}
}
}
namespace A.C
{
using A.B;
class Class2
{
public void DoSomething()
{
= new ();
Class1 x
// The using directive brings A.B.Class1 into scope, as expected.
.DoB();
x}
}
}
This still works as one might inuitively expect. But something surprising happens if we move the using
directive out of the namespace and into the compilation unit. Consider two files:
// File A.cs
namespace A
{
class Class1
{
public void DoA() {}
}
}
namespace A.B
{
class Class1
{
public void DoB() {}
}
}
// File A.C.cs
using A.B;
namespace A.C
{
class Class2
{
public void DoSomething()
{
= new ();
Class1 x
// Surprise! Class1 here is A.Class1, despite our using directive.
.DoA();
x}
}
}
Surprisingly, the Class1
we’re using in A.C.Class2
is actually A.Class1
, even though we have a using A.B
directive at the top of the file.
Why are the names resolved this way?
First, we encounter the using A.B
directive. At this point, Class1
would be resolved as A.B.Class1
.
Next, we enter the A.C
namespace. Remember that this is equivalent to a C
namespace nested in an A
namespace. When we enter the A
namespace, A.Class1
hides A.B.Class1
, and that remains even after we enter the nested C
namespace.
This is one of the rare cases where it really matters where you put your using
directive.