Do not name a class the same as its namespace, Part One
(This is part one of a four part series; part two is here.)
The Framework Design Guidelines say in section 3.4 “do not use the same name for a namespace and a type in that namespace”. (*) That is:
namespace MyContainers.List
{
public class List { … }
}
Why is this badness? Oh, let me count the ways.
Part One: Collisions amongst referenced assemblies:
You can get yourself into situations where you think you are referring to one thing but in fact are referring to something else. Suppose you end up in this unfortunate situation: you are writing Blah.DLL and importing Foo.DLL and Bar.DLL, which, unfortunately, both have a type called Foo:
// Foo.DLL:
namespace Foo { public class Foo { } }
// Bar.DLL:
namespace Bar { public class Foo { } }
// Blah.DLL:
namespace Blah
{
using Foo;
using Bar;
class C { Foo foo; }
}
The compiler gives an error. “Foo” is ambiguous between Foo.Foo and Bar.Foo. Bummer. I guess I’ll fix that by fully qualifying the name:
class C { Foo.Foo foo; }
This now gives the ambiguity error “Foo in Foo.Foo is ambiguous between Foo.Foo and Bar.Foo”. We still don’t know what the first Foo refers to, and until we can figure that out, we don’t even bother to try to figure out what the second one refers to.
This reveals an interesting point about the design of the “type binding” algorithm in C#. That is, the algorithm which determines what type or namespace a name like “X.Y” is talking about. We do not “backtrack”. We do not say “well, suppose X means this. Then Y would have no meaning. Let’s backtrack; suppose X means this other thing, oh, yes, then Y has a meaning.” We figure out what X unambiguously means, and only then do we figure out what Y means. If X is ambiguous, we don’t check all the possibilities to see if any of them has a Y, we just give up.
Assuming you cannot change Foo.DLL, the correct thing to do here is to either remove the “using Foo” – and who knows what all that will break – or to use an extern alias when compiling:
// Blah.DLL:
extern alias FOODLL;
namespace Blah
{
using Foo;
using Bar;
class C { FOODLL::Foo.Foo foo; }
}
Many developers are unfamiliar with the “extern alias” feature. And many of those developers who end up in this situation thereby end up in a cleft stick not of their own devising. Some of them send an angry and profane email to the person who did not cause the problem in the first place, namely, me.
The problem can be avoided in the first place by the authors of Foo.DLL following the guidelines and not naming their type and their namespace the same thing.
Next time: machine-generated code throws a wrench into its own works.
****************
(*) FXCOP flags violations of a far more stringent guideline – FXCOP will tell you if *any* type name conflicts with *any* namespace. But today I’m just talking about the straight-up type-in-a-namespace scenario.
(This is part one of a four part series; part two is here.)
Comments
Anonymous
March 09, 2010
I thought I knew every keyword in the C# language, but I guess I was wrong... I had never heard about "extern alias" (btw, it's not listed on the keywords page on MSDN). Learn something new every day !Anonymous
March 09, 2010
It's listed in a roundabout way: http://msdn.microsoft.com/en-us/library/x53a06bb.aspx "alias" is not a keyword as such (it's a "context keyword"), so it's not listed. But "extern" is listed, and if you follow the link, you'll see a reference to "extern alias" right at the top.Anonymous
March 09, 2010
Why not just make the the C# compiler raise a compiler error if it detects a type inside a namespace with the same name as the parent namespace? Was there a conscious decision to allow it or a reason for it?Anonymous
March 09, 2010
braddabug...It is allowed because it is legal [although a dangerous practice as this shows]. There are other (more complex) scenarios where this also arises where a top level type in one assembly may match a class name in another assembly. This is impossible to detect at the time where the individual assemblies are compiled.Anonymous
March 09, 2010
Vaguely related: What about naming a property the same as a type? The compiler usually has no problems distinguishing between the two but avoiding it at any cost often leads to awkwardly-named properties. I discussed that here: http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx - EricAnonymous
March 09, 2010
braddabug...It is allowed because it is legal [although a dangerous practice as this shows]. There are other (more complex) scenarios where this also arises where a top level type in one assembly may match a class name in another assembly. This is impossible to detect at the time where the individual assemblies are compiled.Anonymous
March 09, 2010
Johannes, Property Names that match Type Names are prevelant throughout the Framework. Just look at most "Control" classes, the Type for a property is most often an exact match for the Property Name.Anonymous
March 09, 2010
The comment has been removedAnonymous
March 09, 2010
The comment has been removedAnonymous
March 09, 2010
Thomas: extern alias is mentioned on MSDN (http://msdn.microsoft.com/en-us/library/ms173212(VS.80).aspx). Notice that you actually have to compile the alias "reference" into the assembly. The most common scenario is when you are stuck having to use two different versions of an assembly. Rare, but possible if you do not properly branch source. Peace and Grace, Greg Twitter: @gbworldAnonymous
March 09, 2010
The comment has been removedAnonymous
March 09, 2010
Where can I read The Framework Design Guidelines? Were you to type that into Bing, it would tell you that you can buy bound copies at Amazon.com, or read them online at http://msdn.microsoft.com/en-us/library/ms229042.aspx. -- EricAnonymous
March 09, 2010
The comment has been removedAnonymous
March 09, 2010
Been there, done that, and it's worse when the VS Designer is involved: http://stackoverflow.com/questions/1259399/alias-and-namespace-conflict-in-visual-studio-designer That's what I'll be discussing next time. -- EricAnonymous
March 10, 2010
The comment has been removedAnonymous
March 10, 2010
Learned new thing "external alias". ThanksAnonymous
March 10, 2010
Thanks for the explanation. That's pretty sneaky all right.Anonymous
March 10, 2010
I find myself often writing code of the following form class DataProperties
{ } class BigFooObject
{
public DataProperties DataProperties { get; private set; }
} which is a similar legal-but-morally-wrong sort of namespacing thing. I keep doing it, and I keep wishing the compiler (well, fxcop really) would slap me every time I do. -mpg No, that's fine. People do that all the time, and the language has been specifically designed to ensure that this is legal and unambiguous. See http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx for details. -- EricAnonymous
March 10, 2010
The comment has been removedAnonymous
March 11, 2010
The comment has been removedAnonymous
March 11, 2010
Just out of curiosity...does it get any worse if you have, for instance, Color.Color.Color?Anonymous
March 11, 2010
Clarifying the previous post. I know that under C# its not allowed to declare a class member with the same name as the class itselft. I was wondering if there could be the case of having to consume a class written in a language where you could define class members with the same name as their enclosing type.Anonymous
March 11, 2010
@Pavel Minaev, @Eric That makes perfect sense.Anonymous
January 08, 2012
Hi Eric, How about this? namespace Project.Json { public static class JSON { .... } }Anonymous
February 10, 2012
The comment has been removed