130
Глава.4 .Основы.типов
поиск повторяется с префиксом
System.Text
. Благодаря двум директивам
using
,
показанным ранее, я смог ограничиться именами
FileStream
и
StringBuilder
—
компилятор автоматически расширяет ссылки до
System.IO.FileStream
и
System.
Collections.StringBuilder
. Конечно, такой код намного проще вводится, чем
исходный, да и читается проще.
Компилятору надо сообщить при помощи параметра
/reference
(см. главы 2
и 3), в каких сборках искать описание типа. В поисках нужного типа компилятор
просмотрит все известные ему сборки. Если подходящая сборка обнаруживается,
сведения о ней и типе помещаются в метаданные результирующего управляемого
модуля. Для того чтобы информация из сборки была доступна компилятору, надо
указать ему сборку, в которой описаны упоминаемые типы. По умолчанию компи-
лятор C# автоматически
просматривает сборку
MSCorLib dll
, даже если она явно не
указана. В ней содержатся описания всех фундаментальных FCL-типов, таких как
Object
,
Int32
,
String
и др.
Легко догадаться, что такой способ обработки пространства имен чреват пробле-
мами, если два (и более) типа с одинаковыми именами находятся в разных сборках.
Microsoft настоятельно рекомендует при описании типов применять уникальные
имена. Но порой это невозможно. В CLR поощряется повторное использование
компонентов.
Допустим, в приложении имеются компоненты, созданные в Microsoft
и Wintellect, в которых есть типы с одним названием, например
Widget
. Версия
Widget
от Microsoft делает одно, а версия от Wintellect – совершенно другое. В этом
случае процесс формирования имен
типов становится неуправляемым, и чтобы
различать эти типы, придется указывать в коде их полные имена. При обращении
к
Widget
от Microsoft надо использовать запись
Microsoft.Widget
, а при ссылке
на
Widget
от Wintellect — запись
Wintellect.Widget
. В следующем коде ссылка на
Widget
неоднозначна, и компилятор C#
выдаст сообщение
error
CS0104
:
'Widget'
is
an
ambiguous
reference
(ошибка CS0104: 'Widget' — неоднозначная ссылка):
using Microsoft;
// Определяем префикс "Microsoft."
using Wintellect; // Определяем префикс "Wintellect."
public sealed class Program {
public static void Main() {
Widget w = new Widget(); // Неоднозначная ссылка
}
}
Для того чтобы избавиться от неоднозначности, надо явно указать компилятору,
какой экземпляр
Widget
требуется создать:
using Microsoft;
// Определяем приставку "Microsoft."
using Wintellect; // Определяем приставку "Wintellect."
public sealed class Program {
public static void Main() {
Wintellect.Widget w = new Wintellect.Widget(); // Неоднозначности нет
}
}
131
Пространства.имен.и.сборки
В C# есть еще одна форма директивы
using
, позволяющая создать псевдоним
для отдельного типа или пространства имен.
Она удобна, если вы намерены ис-
пользовать несколько типов из пространства имен, но не хочется «захламлять»
глобальное пространство имен всеми используемыми типами. Альтернативный
способ преодоления неоднозначности следующий:
using Microsoft; // Определяем приставку "Microsoft."
using Wintellect; // Определяем приставку "Wintellect."
// Имя WintellectWidget определяется как псевдоним для Wintellect.Widget
using WintellectWidget = Wintellect.Widget;
public sealed class Program {
public static void Main() {
WintellectWidget w = new WintellectWidget(); // Ошибки нет
}
}
Эти методы устранения неоднозначности хороши, но иногда их недостаточно.
Представьте, что компании Australian Boomerang Company (ABC) и Alaskan Boat
Corporation (ABC) создали каждая свой тип с именем
BuyProduct
и собираются
поместить его в соответствующие сборки. Не исключено,
что обе компании созда-
дут пространства имен
ABC
, в которые и включат тип
BuyProduct
. Для разработки
приложения, оперирующего обоими типами, необходим механизм, позволяющий
различать программными средствами не только пространства имен, но и сборки.
К счастью, в компиляторе C# поддерживаются
внешние псевдонимы
(extern aliases),
позволяющие справиться с проблемой. Внешние псевдонимы дают также возмож-
ность обращаться к одному типу двух (или более) версий одной сборки.
Подробнее
о внешних псевдонимах см. спецификацию языка C#.
При проектировании типов, применяемых в библиотеках, которые могут ис-
пользоваться третьими лицами, старайтесь описывать эти типы в пространстве имен
так, чтобы компиляторы могли без труда преодолеть неоднозначность типов. Веро-
ятность конфликта заметно снизится, если в пространстве имен верхнего уровня
указывается полное, а не сокращенное название компании. В документации .NET
Framework SDK Microsoft использует для своих типов пространство имен
Microsoft
(например:
Microsoft.CSharp
,
Microsoft.VisualBasic
и
Microsoft.Win32
).
Создавая пространство имен, включите в код его объявление (на C#):
namespace CompanyName {
public sealed class A { // TypeDef: CompanyName.A
}
namespace X {
public sealed class B { ... } // TypeDef: CompanyName.X.B
}
}
В комментарии справа от объявления класса указано реальное имя типа, которое
компилятор поместит в таблицу метаданных определения типов — с точки зрения
CLR это «настоящее» имя типа.