web-dev-qa-db-ja.com

アセンブリを別のアセンブリに埋め込む

他のアセンブリからのものを使用するクラスライブラリを作成する場合、他のアセンブリをクラスライブラリ内に何らかのリソースとして埋め込むことはできますか?

つまりMyAssembly.dllSomeAssembly1.dll、およびSomeAssembly2.dllをファイルシステムに配置する代わりに、他の2つのファイルがバンドルされて- MyAssembly.dllであり、コードで使用できます。


.NETアセンブリが。dllファイルである理由についても少し混乱しています。このフォーマットは.NETより前に存在していませんでしたか?すべての.NETアセンブリがDLLですが、すべてのDLLが.NETアセンブリであるとは限りませんか?なぜ同じファイル形式やファイル拡張子を使用するのですか?

41
xyz

アセンブリのマージについてはILMergeを参照してください。

また、.NETアセンブリが.dllファイルである理由についても少し混乱しています。このフォーマットは.NETより前に存在していませんでしたか?

はい。

すべて.NETアセンブリDLLであり、

DLLまたはEXEのいずれか-通常はnetmoduleでもかまいません。

しかし、すべてのDLLが.NETアセンブリであるとは限りません。

正しい。

なぜ同じファイル形式やファイル拡張子を使用するのですか?

なぜ違うはずなのか-同じ目的を果たす!

35
AtliB

ILMergeはアセンブリのマージを実行しますが、これは素晴らしいことですが、必要な処理が不十分な場合もあります。たとえば、問題のアセンブリが厳密な名前のアセンブリであり、そのアセンブリのキーがない場合、その署名を壊さずにILMergeを実行することはできません。つまり、複数のアセンブリを展開する必要があります。

Ilmergeの代わりに、1つ以上のアセンブリをリソースとしてexeまたはDLLに埋め込むことができます。次に、実行時にアセンブリが読み込まれるときに、埋め込まれたアセンブリをプログラムで抽出し、読み込んで実行できます。トリッキーに聞こえますが、定型コードはほんの少しです。

それを行うには、他のリソース(画像、翻訳ファイル、データなど)を埋め込むのと同じように、アセンブリを埋め込みます。次に、実行時に呼び出されるAssemblyResolverを設定します。スタートアップクラスの静的コンストラクタで設定する必要があります。コードは非常に単純です。

    static NameOfStartupClassHere()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
    }

    static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
    {
        Assembly a1 = Assembly.GetExecutingAssembly();
        Stream s = a1.GetManifestResourceStream(args.Name);
        byte[] block = new byte[s.Length];
        s.Read(block, 0, block.Length);
        Assembly a2 = Assembly.Load(block);
        return a2;
    }

ResolveEventArgsパラメーターのNameプロパティは、解決されるアセンブリの名前です。この名前は、ファイル名ではなくリソースを指します。 「MyAssembly.dll」という名前のファイルを埋め込み、埋め込みリソースを「Foo」と呼ぶと、ここで必要な名前は「Foo」になります。しかし、それは混乱を招くので、リソースの名前にはアセンブリのファイル名を使用することをお勧めします。アセンブリを適切に埋め込み、名前を付けている場合は、アセンブリ名を指定してGetManifestResourceStream()を呼び出し、その方法でアセンブリをロードできます。とても簡単です。

これは、単一の埋め込みアセンブリと同じように、複数のアセンブリで機能します。

実際のアプリでは、そのルーチンでより適切なエラー処理が必要になります。たとえば、指定された名前のストリームがない場合はどうでしょうか。読み取りが失敗した場合はどうなりますか?等。しかし、それはあなたがするために残されています。

残りのアプリケーションコードでは、通常どおりアセンブリの型を使用します。

アプリをビルドするときは、通常どおり、問題のアセンブリへの参照を追加する必要があります。コマンドラインツールを使用する場合は、csc.exeの/ rオプションを使用します。 Visual Studioを使用する場合は、プロジェクトのポップアップメニューで[参照の追加...]を行う必要があります。

実行時に、アセンブリのバージョンチェックと検証は通常どおり機能します。

唯一の違いは分布です。アプリをデプロイまたは配布するときに、埋め込まれた(および参照された)アセンブリに対してDLL)を配布する必要はありません。メインアセンブリをデプロイするだけです。他のアセンブリは配布する必要がないためです。メインに埋め込まれるDLLまたはEXE。

57
Cheeso

あなたはcanアセンブリ(または実際には任意のファイル)をリソースとして埋め込むことができます(そしてそれらにアクセスするためにResourceManagerクラスを使用します)、ただし、アセンブリを組み合わせるだけの場合は、 ILMerge のようなツールを使用することをお勧めします。

EXEとDLLファイルは Windowsポータブル実行可能ファイル であり、.NETコードを含む将来のタイプのコードに対応するのに十分一般的です(DOSでも実行できますが、 DOSでの実行が想定されていないことを示すメッセージを表示します。NETランタイムがまだ実行されていない場合は、それを起動する指示が含まれています。これは、1つのアセンブリが複数のファイルにまたがることも可能です。ほとんどの場合。

7
Mark Cidade

注ILMergeはXAMLのような埋め込みリソースでは機能しないため、WPFアプリなどはCheesoのメソッドを使用する必要があります。

5

Monoプロジェクト が提供するmkbundleユーティリティもあります。

4
hova

なぜ同じファイル形式やファイル拡張子を使用するのですか?

なぜ違うはずなのか-同じ目的を果たす!

ここでの説明の2¢ビット:DLLはダイナミックリンクライブラリです。古いスタイルの.dll(Cコード)と.netスタイルの.dllはどちらも定義上は「ダイナミックリンク」ライブラリです。 .dllは両方の適切な説明です。

1
Eric

Costura.Fody を試してみることをお勧めします。 Costura.Fodyの前にInstall-Package Fodyを忘れないでください(最新のFodyを入手するためです)。

アセンブリをリソースとして埋め込み、AssemblyResolveイベントハンドラーを使用してLoad(byte [])オーバーロードを使用して動的にロードするというCheesoの回答については、リゾルバーを変更して、ロードするアセンブリの既存のインスタンスのAppDomainをチェックし、既に読み込まれている場合は、既存のAssemblyインスタンスを返します。

そのオーバーロードを使用して読み込まれたアセンブリにはコンテキストがないため、フレームワークがアセンブリを複数回再読み込みしようとする可能性があります。すでにロードされているインスタンスを返さない場合、フレームワークはそれらが2つの異なるアセンブリからのものであると見なすため、同じでなければならないが同じではない同じアセンブリコードと型の複数のインスタンスになる可能性があります。

「コンテキストなし」にロードされた同じアセンブリに対して複数のAssemblyResolveイベントが発生する少なくとも1つの方法は、AppDomainにロードされた複数のアセンブリから公開するタイプへの参照がある場合です。これらのタイプを解決する必要があるコードが実行されるためです。

https://msdn.Microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

リンクからのいくつかの顕著なポイント:

"他のアセンブリは、AppDomain.AssemblyResolveイベントを処理しない限り、コンテキストなしで読み込まれるアセンブリにバインドできません。"

「コンテキストなしで同じIDを持つ複数のアセンブリを読み込むと、同じIDを持つアセンブリを複数のコンテキストに読み込むことと同様のタイプIDの問題が発生する可能性があります。複数のコンテキストへのアセンブリの読み込みを回避するを参照してください。」

0
user3447701