#c#
#c#
Вопрос:
У меня есть что-то вроде этого:
namespace n1
{
namespace n2
{
class foo{}
}
}
В другом файле я пишу:
using n1;
Почему я не могу сейчас напечатать что-то вроде:
n2.foo smthing;
И как сделать что-то подобное возможным?
Ответ №1:
Это преднамеренное правило C #. Если вы сделаете это:
namespace Frobozz
{
namespace Magic
{
class Lamp {}
}
class Foo
{
Magic.Lamp myLamp; // Legal; Magic means Frobozz.Magic when inside Frobozz
}
}
Это законно. Но это не:
namespace Frobozz
{
namespace Magic
{
class Lamp {}
}
}
namespace Flathead
{
using Frobozz;
class Bar
{
Magic.Lamp myLamp; // Illegal; merely using Frobozz does not bring Magic into scope
}
}
Правило C #, описывающее это, содержится в разделе 7.6.2 спецификации C # 4. Это очень запутанный раздел; вам нужен абзац ближе к концу, в котором говорится
В противном случае, если пространства имен, импортированные директивами using-namespace- объявления пространства имен, содержат ровно один тип с именем I…
Ключевым моментом является то, что в нем говорится «ровно один тип», а не «точно один тип или пространство имен«. Мы намеренно запрещаем вам «нарезать» имя пространства имен подобным образом, когда вы находитесь за пределами этого пространства имен, потому что это потенциально сбивает с толку. Как говорили другие, если вы хотите сделать что-то подобное, полностью укажите это один раз в директиве using-alias, а затем используйте псевдоним.
Комментарии:
1. Здесь довольно поздно, но… Могу ли я использовать эту область пространства имен для ОПРЕДЕЛЕНИЯ вложенных пространств имен без необходимости использовать полные имена для новых пространств имен? Это значительно упростило бы задачу, избежав дублирования текста и опечаток…
2. @heltonbiker: Звучит как отличный вопрос для StackOverflow … на котором вы уже находитесь. Опубликуйте вопрос!
3. Что ж, вы правы. Интересно, что я попробовал это, и это работает. К сожалению, пространства имен отображаются на панели просмотра классов Visual Studio только в том случае, если внутри них что-то определено (например, класс). Спасибо за ваше внимание!
4. Почему этот ответ не принимается? Принятое, похоже, не имеет отношения к тому, что задается в этом разделе.
5. @wEight: принятый ответ выбирается пользователем, который задал вопрос. Я знаю, это может показаться странным, но часто люди задают вопросы, которые лишь косвенно связаны с проблемой, которая у них действительно есть.
Ответ №2:
Используйте псевдонимы пространств имен:
using n2 = n1.n2;
...
n2.foo something;
Перед именем класса должно быть полное пространство имен (с / или другими именами классов для вложенных типов). Усеченное пространство имен работать не будет.
Ответ №3:
По замыслу, namespaces
они предназначены для того, чтобы помочь вам определить область действия.
Если вы не уточните это полностью, вы получите ошибку, которую видите.
Предполагая, что File1 имеет что-то вроде этого:
namespace n1
{
namespace n2
{
class Foo { }
}
}
Вы можете сделать это двумя способами:
Полностью квалифицированный using
Содержимое File2:
namespace n3
{
using n1.n2;
class TestClass
{
private Foo something;
}
}
Используйте namespace alias
namespace n3
{
using n2 = n1.n2;
class TestClass
{
private n2.Foo something;
}
}
Ответ №4:
Параграф 4 раздела 9.4.2 спецификации языка C # явно объясняет это поведение:
Директива using-namespace- импортирует типы, содержащиеся в данном пространстве имен, но конкретно не импортирует вложенные пространства имен.
Далее даже приводится пример, который очень похож на ваш собственный.
namespace N1.N2
{
class A {}
}
namespace N3
{
using N1;
class B: N2.A {} // Error, N2 unknown
}
Конечно, если бы вы сделали это:
namespace n1
{
public class Example
{
public static void Main()
{
n2.Foo a; // This is legal.
}
}
}
Это было бы скомпилировано, потому что n2
доступно, поскольку на него ссылаются из блока пространства имен предка.
Комментарии:
1. В чем причина этого правила?
2. @Ini Если подумать, то разрешение такого каскадирования пространств имен нарушило бы одну из основных целей использования пространств имен, которая заключается в предотвращении конфликтов имен.
Ответ №5:
Вы не можете написать это, так как n2
находится внутри n1
. Если вы хотите получить доступ к n2
пространству имен, вы можете попробовать ввести using n2 = n1.n2
в начале вашего другого файла.
Ответ №6:
Один из способов сделать это — объявить ваше вложенное пространство имен как класс.
Вы можете иметь:
namespace NS1
{
public class NNS1
{
public class C { }
}
}
namespace NS2
{
public class NNS2
{
public class C { }
}
}
Затем используйте свои пространства имен с помощью:
using NS1;
using NS2;
class C
{
public C()
{
var c1 = new NNS1.C();
var c2 = new NNS2.C();
}
}
Однако это не может создать объединение пространств имен. Если у вас есть:
namespace NS1
{
public class NNS
{
public class C1 { }
}
}
namespace NS2
{
public class NNS
{
public class C2 { }
}
}
И
using NS1;
using NS2;
class C
{
public C()
{
var c1 = new NNS.C1();
var c2 = new NNS.C2();
}
}
Компилятор будет жаловаться на NNS
двусмысленность, поскольку в этом контексте он может ссылаться на два символа класса. Я попытался объявить пространства имен как интерфейсы и использовать класс для их реализации для создания объединения пространств имен. Однако реализация интерфейса не приводит к автоматическому импорту в него символов вложенных классов.
Я не знаю, почему C # не поддерживает ссылку на вложенное пространство имен, и я понятия не имею о недостатках объявления пространств имен как классов. Пожалуйста, прокомментируйте, если кто-нибудь знает.