Có vẻ như bạn đang chọn quá tải thuật ngữ của cả "không gian tên" và "mô-đun". Không có gì ngạc nhiên khi bạn thấy mọi thứ là "gián tiếp" khi chúng không phù hợp với định nghĩa của bạn.
Trong hầu hết các ngôn ngữ hỗ trợ không gian tên, bao gồm C #, không gian tên không phải là mô-đun. Một không gian tên là một cách để phạm vi tên. Các mô-đun là một cách của hành vi phạm vi.
Nói chung, trong khi thời gian chạy .Net hỗ trợ ý tưởng về một mô-đun (với định nghĩa hơi khác so với mô-đun bạn đang sử dụng ngầm), thì nó hiếm khi được sử dụng; Tôi chỉ thấy nó được sử dụng trong các dự án được xây dựng trong SharpDevelop, hầu hết để bạn có thể xây dựng một DLL duy nhất từ các mô-đun được xây dựng bằng các ngôn ngữ khác nhau. Thay vào đó, chúng tôi xây dựng thư viện bằng thư viện được liên kết động.
Trong C #, các không gian tên giải quyết mà không có bất kỳ "lớp gián tiếp" nào, miễn là tất cả chúng đều nằm trong cùng một nhị phân; bất kỳ yêu cầu nào là trách nhiệm của trình biên dịch và trình liên kết mà bạn không cần phải suy nghĩ nhiều. Khi bạn bắt đầu xây dựng một dự án với nhiều phụ thuộc, bạn sẽ tham khảo các thư viện bên ngoài. Khi dự án của bạn đã thực hiện một tham chiếu đến một thư viện bên ngoài (DLL), trình biên dịch sẽ tìm thấy nó cho bạn.
Trong Lược đồ, nếu bạn cần tải một thư viện bên ngoài, bạn phải làm một cái gì đó giống như (#%require (lib "mylib.ss"))
trước tiên, hoặc sử dụng giao diện chức năng nước ngoài trực tiếp, như tôi nhớ. Nếu bạn đang sử dụng các tệp nhị phân bên ngoài, bạn có cùng số lượng công việc để giải quyết các tệp nhị phân bên ngoài. Có thể bạn đã sử dụng hầu hết các thư viện thường được sử dụng đến mức có một shim dựa trên Scheme tóm tắt từ bạn, nhưng nếu bạn phải viết tích hợp của riêng mình với thư viện bên thứ 3, về cơ bản bạn sẽ phải thực hiện một số công việc để "tải " thư viện.
Trong Ruby, Mô-đun, Không gian tên và Tên tệp thực sự ít được kết nối hơn bạn tưởng; LOAD_PATH làm cho mọi thứ hơi phức tạp và khai báo Mô-đun có thể ở bất cứ đâu. Python có lẽ gần gũi hơn để làm mọi thứ theo cách bạn nghĩ bạn đang thấy trong Scheme, ngoại trừ việc các thư viện bên thứ 3 trong C vẫn thêm một nếp nhăn (nhỏ).
Ngoài ra, các ngôn ngữ được nhập động như Ruby, Python và Lisp thường không có cùng cách tiếp cận với "hợp đồng" như các ngôn ngữ được nhập tĩnh. Trong các ngôn ngữ được gõ động, bạn thường chỉ thiết lập một loại "Thỏa thuận của quý ông" mà mã đó sẽ đáp ứng với một số phương thức nhất định và nếu các lớp của bạn có vẻ nói cùng một ngôn ngữ, tất cả đều tốt. Các ngôn ngữ được nhập tĩnh có các cơ chế bổ sung để thực thi các quy tắc này tại thời gian biên dịch. Trong C #, sử dụng hợp đồng như vậy cho phép bạn cung cấp ít nhất các đảm bảo hữu ích vừa phải về việc tuân thủ các giao diện này, cho phép bạn đóng gói các plugin và thay thế với một mức độ đảm bảo tính phổ biến vì tất cả các bạn đều biên dịch theo cùng một hợp đồng. Trong Ruby hoặc Scheme, bạn xác minh các thỏa thuận này bằng cách viết các bài kiểm tra hoạt động trong thời gian chạy.
Có một lợi ích hiệu suất có thể đo được từ các đảm bảo thời gian biên dịch này, vì một yêu cầu phương thức không yêu cầu gửi kép. Để có được những lợi ích này trong một cái gì đó như Lisp, Ruby, JavaScript hoặc các nơi khác, hiện tại vẫn còn các cơ chế hơi kỳ lạ của các lớp biên dịch tĩnh chỉ trong các máy ảo chuyên dụng.
Một điều mà hệ sinh thái C # vẫn có sự hỗ trợ tương đối non nớt là việc quản lý các phụ thuộc nhị phân này; Java đã có Maven trong vài năm để đảm bảo rằng bạn có tất cả các phụ thuộc cần thiết của mình, trong khi C # vẫn có một cách tiếp cận giống như MAKE khá nguyên thủy, bao gồm chiến lược đặt các tệp vào đúng vị trí trước thời hạn.