Что C# компилируется при использовании пространств имен - PullRequest
1 голос
/ 27 мая 2020

У нас есть два приложения, каждое из которых компилирует свой собственный код, при этом часть кода используется совместно (в основном, связанная с данными). Казалось естественным разделить этот дизайн на три пространства имен и попытаться применить это пространство имен Foo никогда не импортирует пространство имен Bar, но может импортировать пространство имен Shared.

Я надеюсь, что диаграммы Венна будут оценены как визуализация : enter image description here

Однако один из классов между Foo и Bar проскочил сквозь трещины, и кто-то сослался на класс из Bar внутри Foo, несмотря на принудительное применение.

И это заставило меня задуматься, как компилятор C# на самом деле справляется с этим? На мой взгляд, может произойти одно из двух.

  1. Все пространство имен компилируется в Foo. Оставьте диаграмму так: enter image description here
  2. Или компилятор достаточно умен, чтобы извлечь необходимый класс. Как сделать диаграмму такой: enter image description here

Кажется, я не могу найти никакой документации о том, как компилируются использования и пространства имен. Похоже, что пространства имен предназначены только для организации кода для разработчиков, а не для компиляторов. Тем не менее, они предоставляют возможности ... Так что, я думаю, тогда применим №2? Как это вообще проверить?

1 Ответ

2 голосов
/ 27 мая 2020

Между пространствами имен и сборками нет соответствия: одна сборка может содержать много пространств имен, а одно пространство имен может охватывать несколько сборок.

Скомпилированный код IL в сборке обращается к типам по их полным именам: Foo.SomeClass вместо SomeClass, Bar.OtherClass вместо OtherClass и т. Д. Задача компилятора - определить , какое полное имя типа вы действительно имеете в виду, когда пишете сокращенную форму SomeClass - потому что вы могли бы определить класс с именем SomeClass в пространствах имен Foo, Bar или даже System!

Когда вы пишете:

namespace Foo
{
    public class SomeClass
    {
    }
}

Вы определяете тип с полным именем Foo.SomeClass.

Когда вы пишете:

using Foo;
...
SomeClass instance = new SomeClass();

Компилятор обрабатывает это так же, как:

Foo.SomeClass instance = new Foo.SomeClass();

Пространства имен - это просто удобная конструкция для организации этих полностью определенных имен. Когда вы говорите using Foo;, вы просто говорите компилятору искать полностью определенные имена, которые начинаются с Foo., когда вы набираете SomeClass. Когда вы пишете using Foo;, ничего не «импортируется», это просто удобная альтернатива написанию Foo.SomeClass везде; а также ваш using s или ваш namespace s не генерирует никакого "кода" (в смысле испускаемых инструкций IL). Все, что он делает, это говорит компилятору помещать Foo.SomeClass в IL всякий раз, когда вы пишете SomeClass.

Вышеупомянутое является упрощением более детального набора правил, определенных в spe c для разрешения коротких -формировать имена типов; вы можете прочитать это для получения более подробной информации: здесь и здесь

Уровень, на котором вы хотите обеспечить соблюдение зависимостей в своих диаграммах, будет указан в ссылке на сборку уровень: если проект Foo никогда не ссылается на сборку Bar или наоборот, код даже не скомпилируется, если вы попытаетесь ссылаться на тип в одной сборке из другой. Пространства имен на самом деле не имеют к этому никакого отношения, потому что, опять же, ничто не мешает вам определять типы в пространстве имен Foo, а только в сборке Bar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...