web-dev-qa-db-ja.com

「ローカルコピー」はプロジェクト参照に対して推移的ですか?

- に関して。提案された重複:この質問は リンクされた質問 の反対を示唆しているので、 not 重複だと思います。

最初、私は読みました 「ローカルコピー」のベストプラクティスとプロジェクト参照を使用しますか? (また this )そして私はとにかくこれを試してみるために、しかしこれに関する一般的なフィードバックを得る必要があるようです docs このようなものはひどいですそして私はVS2010だけを使っていますそして多分彼らは新しいバージョンで何かを変更しました知っている。

Second、私は project references にのみ興味があります。私は GACからのアセンブリは異なる方法で処理されることを読んでください そしてGACは私の問題とは無関係です。

Third、提案された重複を読んだ後、しかしもっとそうニース answer ここ@Albireoによって、ファイルを区別することも重要であるように見えます依存関係。依存関係はdllアセンブリファイルを参照し、 project 依存関係(つまり、私が質問しているもの)は、依存関係はを参照します。 project および暗黙的にそのプロジェクトの出力ファイル。

とにかく、これが状況です。私が思うに少し変わっていますが、それでも:

  • 2つのC#実行可能プロジェクト
  • n C#dllアセンブリプロジェクト
  • 2つの実行可能ファイルは、別々にデプロイされるため、出力ディレクトリが異なります。そのため、開発者のマシンでも別々になります。
  • 2つの実行可能ファイルは、いくつかのDLLアセンブリ(相互に依存している可能性があります)に依存しています)
  • 3つの出力ディレクトリがあります:
    • 実行可能ファイル1プロジェクトの場合は/x1
    • 実行可能ファイル2プロジェクトの場合は/x2
    • /libすべてのdllアセンブリ

DLLアセンブリ all は、すべて同じ出力にビルドされるため、プロジェクト参照用にCopy Localfalseに設定しますディレクトリ。

2 実行可能プロジェクトは、参照するすべてのDLLアセンブリプロジェクト参照に対してCopy Localtrueに設定しましたDLLがそれぞれ/x1/x2にコピーされるように直接。

質問今はwrtです。 実行可能プロジェクトによって直接参照されていないであるが、参照されているアセンブリを介して推移的にのみであるDLLへ:アセンブリ、 「ローカルコピー」 is setの場合、 only は別のアセンブリを介して推移的に参照され、実行可能ファイルの出力フォルダーにコピーされます最初のアセンブリで本当ですか?

例:

  • x1.csproj(例:出力= x1/one.exe
    • 参照:dlA.csproj(例:出力= lib/a.dll)とCopy Local = *true*
    • (b.dllに直接参照はありません)
  • dlA.csproj(例:出力= lib/a.dll
    • 参照:dlB.csproj(例:出力= lib/b.dll)とCopy Local = **false**
    • (c.dllへの直接参照はありません)
  • dlC.csproj(例:出力= lib/c.dll
    • (これ以上の関連する参照はありません)

したがって、one.exe -> a.dll -> b.dll -> c.dllの論理依存関係があり、a.dllのみがone.exeの出力ディレクトリに明らかにコピーされます。 他の2つのdllも出力ディレクトリにコピーされますか?これはどこかに文書化されていますか?


そして、はい、私はそれを試しました。そして、はい、それは動作しているようですですが、私はまだそれを十分に突っ込んでおらず、とにかく私が見逃したかもしれない何かがあります。 (また、公式ドキュメントに関する質問もあります。)

30
Martin Ba

また、依存関係がdllアセンブリファイルとプロジェクトの依存関係(つまり、私が求めているもの)を参照するファイルの依存関係を区別することが重要であるように見えます。依存関係はプロジェクトを参照し、暗黙的にそのプロジェクトの出力ファイルを参照します。

そうではありません。

MSBuildは、参照がソリューション内の別のプロジェクトを指しているのか、DLLを指しているのかを実際には気にしません。

ProjectAProjectBに依存してビルドする場合ProjectAProjectBはすでにビルドされている(そして最新である)必要がある場合、MSBuildはそのDLL(C#コードではありません)そしてそれをProjectAにリンクします。

DLLの代わりにプロジェクト参照を追加することは、便宜上「シンタックスシュガー」です。このようにして、MSBuildは、出力が何であれ、参照されるプロジェクトの出力を選択する必要があることを認識します。

それ以外の場合は、依存関係を手動で事前ビルドし、そのDLLを見つけてプロジェクトにリンクし、ビルド構成を切り替えたり、移動したり、名前を変更したりするたびにプロセスを繰り返す必要があります。あまり実用的ではありません。

他の2つのdllも出力ディレクトリにコピーされますか?

依存関係の要素が、アセンブリが参照されているプロジェクトから直接使用されている場合、その参照がコピーされます。

例として、次のソリューションレイアウトがあります。

  • MySolution
    • MySolution.ConsoleApplication
    • MySolution.FirstDependency
    • MySolution.SecondDependency
    • MySolution.ThirdDependency
    • MySolution.FourthDependency

この依存関係チェーンの場合:

  • MySolution.ConsoleApplication
    • MySolution.FirstDependency
      • MySolution.SecondDependency
        • MySolution.ThirdDependency
        • MySolution.FourthDependency

このソリューションをビルドすると、MySolution.ConsoleApplication出力ディレクトリにMySolution.FirstDependencyMySolution.SecondDependency、およびMySolution.ThirdDependencyのDLLがありますが、MySolution.FourthDependencyのDLLはありません。

なぜそうなのですか? MSBuildがMySolution.SecondDependencyをビルドすると、MySolution.FourthDependencyに宣言された依存関係があることに気付きますが、MySolution.FourthDependencyコード内のMySolution.SecondDependencyからの要素の使用法が見つからないため、何らかの「最適化」を実行することにします。そして、出力からMySolution.FourthDependency Assemblyを省略します。

これと同じ問題が過去にNuGetAutoMapperを介して「深い依存関係」に追加したときに私を悩ませました。AutoMapperを追加すると、2つのアセンブリ参照AutoMapperAutoMapper.Net4が追加され、2番目のアセンブリは最初のアセンブリによって最初のアセンブリによって読み込まれます。 .NET Framework 4によって導入された新しいコレクションオブジェクトに対して特定の種類のアクションを実行する必要があります。2番目のアセンブリはリフレクションを介して読み込まれるため、MSBuildは未使用であると見なし、わざわざコピーする必要はありません。

つまり、yes、直接使用している限りコピーされますリフレクションではありません。

これはどこかに文書化されていますか?

この動作はMSBuildの「機能」のようです。この問題が発生したときに、Microsoftの何人かの人々によるブログ投稿を見つけることができましたが、現時点では再び見つけることができません。

27
Albireo

それは非常に簡単で、ローカルコピーとは何の関係もありません。 MSBuildは、アセンブリのメタデータを調べて、アセンブリの依存関係を確認します。アセンブリでildasm.exeを実行し、マニフェストをダブルクリックします。洞察を得るためにこれを試してみてください。 .Assemblyディレクティブが表示されます。コンパイラがアセンブリをビルドしたときに挿入され、コードで実際に使用した参照アセンブリのみが一覧表示されます。

MSBuildが同じディレクトリでそのようなアセンブリを見つけることができる場合、MSBuildはそれを自動的にコピーします。そうでない場合は、サイレントコピーをスキップします。

これから、故障モードを推測できます。アンマネージDLLはコピーできず、メタデータには表示されません。 Assembly.Load/From()を介して間接的に依存しているアセンブリをコピーすることはできません。また、メタデータにも表示されません。まだビルドされていないアセンブリをコピーすることはできません。ビルド順序の問題です。また、CopyLocalプロパティをFalseに設定したアセンブリをコピーすることはできません。これは通常、アセンブリがGACに存在する場合にのみ有効な選択であり、コピーは必要ありません。

あなたが助ける必要があるそのような場合のために、ビルド後のイベントのXCOPYは仕事を成し遂げます。

19
Hans Passant