.NETモジュールがモジュールファイル名を名前空間から分離するのはなぜですか?


9

Schemeプログラミング言語(R6RS標準)の実装では、次のようにモジュールをインポートできます。

(import (abc def xyz))

システムは、ファイルを検索しようとするあなたのスキームモジュールを維持するいくつかのディレクトリです。モジュールのソースコードであり、必要に応じてオンザフライでコンパイルされます。$DIR/abc/def/xyz.sls$DIRxyz.sls

Ruby、Python、およびPerlモジュールシステムは、この点で似ています。

一方、C#はもう少し複雑です。

まず、プロジェクトごとに参照する必要があるdllファイルがあります。それぞれを明示的に参照する必要があります。これは言うよりも複雑で、ディレクトリにdllファイルをドロップし、C#に名前でピックアップさせます。

次に、dllのファイル名と、dllによって提供される名前空間との間に1対1の名前の対応はありません。この柔軟性は高く評価できますが、手に負えなくなる可能性もあります。

これを具体的にするために、私がこれを言うときusing abc.def.xyz;、C#がC#がabc/def/xyz.dll参照することを知っている(プロジェクトごとに構成可能)ディレクトリでファイルを見つけようとするとよいでしょう。

Ruby、Python、Perl、Schemeのモジュール処理方法の方がエレガントだと思います。新興言語はより単純な設計で行く傾向があるようです。

.NET / C#の世界が、このようにして、間接レベルをさらに上げているのはなぜですか?


10
.NETのアセンブリおよびクラス解決メカニズムは、10年以上にわたって問題なく機能しています。それがそのように設計されている理由についての根本的な誤解がない(または十分な研究がない)と思います。たとえば、バインド時のアセンブリのリダイレクトなど、その他の多くの有用な解決メカニズムをサポートします
Kev

私は、usingステートメントからのDLL解決が並列実行を中断することを確信しています。また、1対1の場合、mscorlibのすべての名前空間に50のdllが必要か、名前空間の概念を落とさなければならない
Conrad Frix

追加レベルの間接参照?Hmmmmm .... dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html
user541686

@gilles質問の編集と改善をありがとう!
dharmatech 2012年

いくつかのポイントはVisual Studioに固有であり、それらを言語と比較することはかなり公平ではありません(たとえば、プロジェクトでのDLL参照)。完全な.NET環境のより良い比較は、Java + Eclipseです。
ロスパターソン

回答:


22

フレームワーク設計ガイドラインセクション3.3 の次の注釈。アセンブリとDllの名前は、名前空間とアセンブリが分離している理由についての洞察を提供します。

BRAD ABRAMS CLRの設計の早い段階で、プラットフォーム(名前空間)の開発者ビューを、プラットフォーム(アセンブリ)のパッケージ化および展開ビューから分離することにしました。この分離により、それぞれを独自の基準に基づいて個別に最適化できます。たとえば、機能的に関連するタイプ(たとえば、System.IOのすべてのI / O要素)をグループ化するために名前空間を自由に因数分解できますが、パフォーマンス(読み込み時間)、展開、サービス、またはバージョン管理の理由でアセンブリを因数分解できます。


これまでのところ最も権威のある情報源のようです。コンラッドありがとう!
dharmatech 2012年

のろわれた権威ある答えを得るための+1。しかし、「C#が<X>を実行する理由」の質問もすべて、「Javaが<X>を実行する<X>のレンズを介して次のように表示する必要があります:...」。 Windows上のJavaに対するMicrosoftのさまざまなアジェンダ。
ロスパターソン

6

柔軟性が追加され、ライブラリ(質問ではモジュールと呼ぶもの)をオンデマンドでロードできます。

1つの名前空間、複数のライブラリ:

利点の1つは、あるライブラリを別のライブラリに簡単に置き換えることができることです。名前空間と、データベースに固有のSQLクエリやその他のものをすべて含むMyCompany.MyApplication.DALライブラリDAL.MicrosoftSQL.dllがあるとします。アプリケーションにOracleとの互換性を持たせたい場合はDAL.Oracle.dll、同じ名前空間を維持したままを追加するだけです。これからは、Microsoft SQL Serverとの互換性を必要とするお客様向けの1つのライブラリと、Oracleを使用するお客様向けのもう1つのライブラリを備えたアプリケーションを提供できます。

このレベルで名前空間を変更すると、コードが重複するかusing、各データベースのソースコード内のすべてのを変更する必要が生じます。

1つのライブラリ、複数の名前空間:

1つのライブラリに複数の名前空間があることも、読みやすさの点で有利です。クラスで、名前空間の1つだけを使用する場合は、この名前空間のみをファイルの先頭に配置します。

  • 大規模なライブラリのすべての名前空間を持つことは、ソースコードを読む人にとっても、ライター自身にとっても混乱を招き、Intellisenseは特定のコンテキストで示唆することが多すぎるためです。

  • ライブラリが小さい場合、ファイルごとに1つのライブラリがパフォーマンスに影響します。各ライブラリは、必要に応じてメモリにロードし、アプリケーションの実行時に仮想マシンで処理する必要があります。ロードするファイルが少ないほど、パフォーマンスがわずかに向上します。


2番目のケースでは、ファイル名を名前空間から分離する必要はありません(そのような分離を許可すると分離が大幅に容易になります)。これは、特定のアセンブリに多数のサブフォルダーとファイルを簡単に含めることができるためです。さらに、複数のアセンブリを同じDLLに埋め込むこともできます(たとえば、ILMergeを使用)。Java Worksはこのアプローチを採用しています。
ブライアン、

2

「名前空間」と「モジュール」の両方の用語をオーバーロードすることを選択しているようです。定義に適合しない場合に「間接的」と見なされるのは当然のことです。

C#を含む名前空間をサポートするほとんどの言語では、名前空間はモジュールではありません。名前空間は名前をスコープする方法です。モジュールはスコープ動作の方法です。

一般に、.Netランタイムはモジュールの概念をサポートしますが(暗黙的に使用しているものとは少し異なる定義で)、それはめったに使用されません。SharpDevelopでビルドされたプロジェクトで使用されるのを見ただけで、主に、さまざまな言語でビルドされたモジュールから単一のDLLをビルドできました。代わりに、動的にリンクされたライブラリを使用してライブラリを構築します。

C#では、名前空間は、同じバイナリ内にある限り、「間接層」なしで解決されます。必要な間接処理は、コンパイラやリンカの責任であり、あまり考慮する必要はありません。複数の依存関係を持つプロジェクトの構築を開始したら、外部ライブラリを参照します。プロジェクトが外部ライブラリ(DLL)への参照を作成すると、コンパイラがそれを見つけます。

Schemeでは、外部ライブラリをロードする必要がある場合、(#%require (lib "mylib.ss"))最初に何かをするか、外部関数インターフェイスを直接使用する必要があります。外部バイナリを使用している場合、外部バイナリを解決するために同じ量の作業が必要です。ほとんどの場合、使用頻度の高いライブラリを使用していて、それを抽象化するSchemeベースのシムがありますが、サードパーティライブラリとの独自の統合を作成する必要がある場合は、基本的に「ロードする」ための作業が必要になります。 " 図書館。

Rubyでは、モジュール、名前空間、およびファイル名は、実際には、想定しているように接続されていません。LOAD_PATHは少し複雑になり、モジュール宣言はどこにでも置くことができます。Pythonはおそらく、Schemeで見ていると思う方法に近いですが、Cのサードパーティライブラリがまだ(小さな)しわを追加している点が異なります。

さらに、Ruby、Python、Lispのような動的に型付けされた言語には、通常、静的に型付けされた言語と同じ「契約」へのアプローチがありません。動的に型付けされた言語では、通常、コードが特定のメソッドに応答する一種の「紳士協定」のみを確立します。クラスが同じ言語を話しているように見える場合、すべてが適切です。静的型付け言語には、コンパイル時にこれらのルールを適用するための追加のメカニズムがあります。C#では、そのようなコントラクトを使用することで、これらのインターフェイスの順守について少なくとも適度に有用な保証を提供できます。これにより、すべてが同じコントラクトに対してコンパイルされるため、プラグインと置換をある程度の共通性の保証とともにバンドルできます。RubyまたはSchemeでは、実行時に機能するテストを作成して、これらの合意を検証します。

メソッドの呼び出しには二重ディスパッチが必要ないため、これらのコンパイル時間の保証から測定可能なパフォーマンス上の利点があります。Lisp、Ruby、JavaScript、または他の場所でこれらの利点を得るには、今でも特殊なVMでジャストインタイムの静的コンパイルクラスのわずかにエキゾチックなメカニズムであるものが必要です。

C#エコシステムがまだ比較的未熟なサポートを持っていることの1つは、これらのバイナリ依存関係の管理です。Javaは数年前からMavenを使用して必要な依存関係をすべて確実に処理していましたが、C#にはまだ事前に適切な場所にファイルを戦略的に配置するというかなり基本的なMAKEのようなアプローチがあります。


1
依存関係の管理については、NuGetをご覧ください。ここだ素晴らしい記事フィル・ハークからそれについて
コンラッドFrix

私が使用したR6RSスキームの実装(Ikarus、Chez、Ypsilonなど)では、ライブラリのインポートに基づいて依存関係が自動的に処理されます。依存関係が見つかり、必要に応じて、将来のインポートのためにコンパイルおよびキャッシュされます。
dharmatech 2012年

Nugetに精通しているため、「比較的未成熟」だというコメント
JasonTrue
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.