Не давайте классам и пространствам имен одинаковые названия. Часть 2

Часть 2: Автоматически сгенерированный код

Вы написали

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

Вы берете этот код и с помощью стороннего инструмента «декоратора» превращаете свой класс в более красочный:

// Автоматически сгенерированный код:
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); }
  }
}

И, возможно, какой-то дополнительный код, такой как операторы неявного преобразования к классу Foo или из класса Foo и т.п. Конкретные подробности этого инструмента здесь не важны, а важно лишь то, что этот код генерируется компьютером.

Авторы генератора кода считали себя умными, поэтому полностью квалифицировали имена всех типов, но они оказались недостаточно умными. На самом деле, все эти имена должны были начинаться с “global::”. А в таком виде код не будет компилироваться. В результате компиляции будет выдано чрезвычайно малополезное сообщение «тип Foo не существует в Foo.Foo».

Что? Конечно кажется, что тип Foo точно существует в Foo… или, постойте. Внутри пространства имен Foo, тип с именем “Foo.Foo” означает «нечто с именем Foo внутри типа Foo», и внутри пространства имен Foo.

Забавно, это как хороший совет, которого вы просто не послушали: в этом случае разработчики кодогенератора лучше бы не квалифицировали имена полностью.

Теперь пользователь опять в безвыходном положении не по своей вине. Этот код генерируется компьютером и в него нельзя с легкостью вносить изменения, поскольку позднее он будет сгенерирован заново, что приведет к потере всех изменений.

Теперь вы можете сказать, ну что же, это ошибка в генераторе кода. Но такие генераторы кода существуют. Я, кстати, однажды допустил такую же ошибку в генераторе кода, хотя, к счастью понял свою ошибку до окончательного выпуска продукта. Эту ошибку совершить весьма просто, и многие существующие генераторы кода не квалифицируют все свои типы с помощью префикса “global::”. (*)

Прежде всего, не стоит допускать таких проблем. Вы можете избежать их, если не будете давать своим классам и пространствам имен одинаковых названий.

Это происходит на удивление часто. Наши собственные тестеры, проверяя генераторы кода, заново находили ее несколько раз, и часто считали ее ошибкой алгоритма поиска типов компилятора, а не проблемой генератора кода.

В следующей статье: как проектировать неудачные иерархии.

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

(**) И конечно же, многие генераторы кода были написаны в дни C# 1.0 до изобретения “global::”.

Оригинал статьи