Похоже, вы решили перегружать терминологию «пространства имен» и «модуля». Не должно быть сюрпризом, что вы видите вещи как «косвенные», когда они не соответствуют вашим определениям.
В большинстве языков, которые поддерживают пространства имен, включая C #, пространство имен не является модулем. Пространство имен - это способ определения имен. Модули - это способ определения поведения.
В целом, хотя среда выполнения .Net поддерживает идею модуля (с определением, немного отличающимся от того, который вы неявно используете), он используется довольно редко; Я видел его только в проектах, созданных в SharpDevelop, главным образом для того, чтобы вы могли собрать одну DLL из модулей, построенных на разных языках. Вместо этого мы создаем библиотеки с использованием динамически связанной библиотеки.
В C # пространства имен разрешаются без какого-либо «уровня косвенности», если они все находятся в одном двоичном файле; Ответственность за любое косвенное обращение лежит на компиляторе и компоновщике, о котором вам не нужно много думать. Как только вы начинаете создавать проект с несколькими зависимостями, вы затем ссылаетесь на внешние библиотеки. Как только ваш проект сделал ссылку на внешнюю библиотеку (DLL), компилятор найдет ее для вас.
В Схеме, если вам нужно загрузить внешнюю библиотеку, вы должны (#%require (lib "mylib.ss"))
сначала сделать что-то подобное или использовать интерфейс сторонней функции напрямую, насколько я помню. Если вы используете внешние двоичные файлы, у вас есть такой же объем работы для разрешения внешних двоичных файлов. Скорее всего, вы в основном использовали библиотеки, которые так часто используются, что есть схема, основанная на Scheme, которая абстрагирует вас от этого, но если вам когда-нибудь понадобится написать собственную интеграцию со сторонней библиотекой, вам, по сути, придется поработать над «загрузкой». " библиотека.
В Ruby Модули, Пространства имен и Имена файлов на самом деле гораздо менее связаны, чем кажется; LOAD_PATH делает вещи немного сложнее, и объявления модулей могут быть где угодно. Python, вероятно, ближе к тому, чтобы делать вещи так, как вы думаете в Scheme, за исключением того, что сторонние библиотеки в C по-прежнему добавляют (маленькую) складку.
Кроме того, языки с динамической типизацией, такие как Ruby, Python и Lisp, обычно не имеют такой же подход к «контрактам», как языки со статической типизацией. В динамически типизированных языках вы обычно устанавливаете своего рода «соглашение Джентльмена», что код будет реагировать на определенные методы, и, если кажется, что ваши классы говорят на одном языке, все хорошо. Языки со статической типизацией имеют дополнительные механизмы для обеспечения соблюдения этих правил во время компиляции. В C # использование такого контракта позволяет вам предоставлять как минимум умеренно полезные гарантии соблюдения этих интерфейсов, что позволяет связывать плагины и замены с некоторой степенью гарантии общности, поскольку все вы компилируете по одному и тому же контракту. В Ruby или Scheme вы проверяете эти соглашения путем написания тестов, которые работают во время выполнения.
Эти гарантии времени компиляции дают ощутимый выигрыш в производительности, так как вызов метода не требует двойной отправки. Для того, чтобы получить эти преимущества в чем-то вроде Lisp, Ruby, JavaScript или где-то еще, требуется то, что сейчас все еще является немного экзотическими механизмами статического компиляции классов точно в срок в специализированных виртуальных машинах.
Одна вещь, которую экосистема C # все еще имеет относительно незрелую поддержку, - это управление этими бинарными зависимостями; В течение нескольких лет в Java Maven работал над тем, чтобы убедиться, что у вас есть все необходимые зависимости, в то время как в C # все еще существует довольно примитивный MAKE-подобный подход, который предполагает стратегическое размещение файлов в нужном месте заранее.