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