Freigeben über


Do not name a class the same as its namespace, Part Two

(This is part two of a four part series; part one is here, part three is here.)

Part Two: Machine-generated code:

You write

namespace Foo
{
public sealed class Foo
{
public string Blah(int x) { … }
}
}

You take this code and run a third-party “decorator” tool over it that makes your class into a more colourful class:

// Machine-generated code:
namespace Foo
{
public sealed class ColorFoo
{
public ColorFoo(Foo.Foo foo, System.Drawing.Color color)
{
innerFoo = foo;
innerColor = color;
}
private Foo.Foo innerFoo;
private System.Drawing.Color innerColor;
public System.Drawing.Color Color { get { return innerColor; } }
public string Blah(int x) { return innerFoo.Blah(x); }
}
}

And maybe some other stuff in there like an implicit conversion to or from Foo, and so on. The exact details of the decorator aren’t important here; what’s important is that this code was generated by a machine.

The authors of the code generator thought they were being clever and fully qualifying all the type names, but they were not clever enough. Those type names should actually be fully qualified with “global::” on the front of all of them. The code as it stands will not compile; it gives the incredibly unhelpful message “type name Foo does not exist in Foo.Foo”. 

Uh, what? It sure looks like a type named Foo exists in Foo… oh, wait. Inside namespace Foo, the name “Foo.Foo” means “the thing named Foo inside type Foo”, and we’re inside namespace Foo.

It’s ironic, like good advice that you just didn’t take: the code generator writers would have been better off not qualifying the names in this case.

Now the user is again in a cleft stick not of their own devising; the code is machine-generated and probably cannot easily be edited because its just going to be re-generated again later and the edits will be lost. 

Now, you might say, well, this is a bug in the code generator. There exist such code generators; I actually wrote this bug into a code generator once, though fortunately I realized my mistake before we shipped. It’s really easy to do, and lots of existing code generators do not fully qualify their type names all the way out to “global::”. (*)

But still, better to not cause trouble for code generators in the first place; you can avoid the problem by not naming the class and the namespace the same thing.

This scenario happens surprisingly often. Our own testers have rediscovered this one independently several times when they’ve been doing testing on code generators, and often believe it to be a bug in the compiler’s type lookup algorithm, not a flaw in the code generator.

Next time: how to design a bad hierarchy

*************

(**) And of course many code generators were written in the C# 1.0 days before the “global::” syntax was invented.

(This is part two of a four part series; part one is here, part three is here.)

Comments

  • Anonymous
    March 11, 2010
    "Next time: how to design a bad hierarchy" I hope this will offer some insight on how to design a good hierarchy. ;)

  • Anonymous
    March 11, 2010
    The comment has been removed

  • Anonymous
    March 11, 2010
    What's a cleft stick? Where can I get one?

  • Anonymous
    March 11, 2010
    "like good advice that you just didn’t take" : http://www.youtube.com/watch?v=nT1TVSTkAXg

  • Anonymous
    March 11, 2010
    The comment has been removed

  • Anonymous
    March 12, 2010
    Is "sealed" actually part of the example? Because I would argue that unless it makes a difference, it is visual noise that doesn't belong. I understand that sealing your classes by default is "best practices", but its conspicuous existence here makes me think "Oh, I can avoid this problem just by not sealing my classes". It is there to motivate the reason for my choice to make the code generator extend the class through aggregations rather than inheritance. There could be any number of reasons why it is not appropriate to extend through inheritance; the class being sealed is one of them. (This point might have been too subtle.) One can of course run into similar issues when extending a class through inheritance. -- Eric

  • Anonymous
    March 12, 2010
    The comment has been removed

  • Anonymous
    March 13, 2010
    It's getting better in a sense that, in the past, there was simply no single definite solution for template code generation (and any template text generation) on .NET. The only thing you could do with stock framework is to rig up ASP.NET, but it really isn't designed for that kind of thing, and the whole scheme gets ugly real quick. So, most generators ended up being driven entirely from hand-written code using CodeDOM. Now? There's T4 (http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx). And in VS2010, there are pre-compiled T4 templates, which are much easier to use. So now that there's a clear single choice for this feature on the platform, there's more incentive to use it - and that generally implies making source templates themselves available for customization. Of Microsoft own offerings, ASP.NET MVC already does so (http://blogs.msdn.com/webdevtools/archive/2009/01/29/t4-templates-a-quick-start-guide-for-asp-net-mvc-developers.aspx).

  • Anonymous
    March 13, 2010
    The comment has been removed

  • Anonymous
    March 14, 2010
    do appriciate your advice, If you have time, will love to read your views on the following. http://stackoverflow.com/questions/2434788/how-do-you-resolve-the-common-naming-collision-between-type-and-object/2434860#2434860

  • Anonymous
    March 24, 2010
    Hold on a tick, ColorFoo is sealed but NOT immutable via readonly on its private fields?  A buggy code generator indeed!