5

多くの F# および C# プロジェクトのソリューションがあります。私の目標は、ILMerge を使用してそれらすべてを 1 つのライブラリにマージすることです。結果としてマージされた dll は NuGet パッケージに配置され、他のプロジェクトで参照されます。ただし、マージされた dll が F# プロジェクトで参照されている場合、いくつかの問題が発生しています。

私が抱えている問題は、ILMerge に指定されたプライマリ アセンブリが F# の場合、F# プロジェクトで結果の dll を参照すると、F# 型にしかアクセスできないことです。C# dll がマージのプライマリ アセンブリとして選択されている場合、F# プロジェクトで参照するときに、マージされた F# アセンブリの拡張メソッドを使用できませんでした。また、属性を持つモジュールは、AutoOpen囲んでいる名前空間を開くときに暗黙的に開かれなくなりました。

F# と C# のアセンブリをマージして、すべての型 (拡張メソッドを含む) を利用できるようにする方法はありますか?

4

1 に答える 1

4

私たちのコード ベースの一部では、ライブラリの大部分が F# で作成され、残りは C# で作成されています。F# と C# のコードはどちらも正面向きです。

マージを処理するための地獄のようなバッチ ファイルがあり、次のコードでマージしていることがわかります。

echo merging %mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"
%mergeapp% /keyfile:"%keyfile%" /target:library /attr:"%dstpath%%csharpdll%" /targetplatform:%targetplatform%,%targetlib% /lib:%sllib% /lib:%targetlib% /lib:"%libpath%lib" /out:"%mergedpath%..\%csharpdll%" "%dstpath%%csharpdll%" "%dstpath%%fsharpdll%"

そして、それは私たちが意図したことを行います。ただし、拡張メソッドを公開したり、AutoOpen を行ったりすることはありません。私たちが発見したのは、F# コンパイラのバグでした。難読化を組み合わせ始めるまではildasm、F# アセンブリで実行し、問題のあるコードを取り除く必要がありました。もう 1 つの問題は、F# がメンバーの protected 修飾子を適切にサポートしていないことです (F# はそれらをパブリックにします)。そのため、保護されることを意図したクラス メンバーに掛けることができる属性を作成しました。次に、Cecil を使用してアセンブリを爆破し、属性を取り除き、それらのメンバーへのアクセスを保護されたものに変更するツールを作成しました (コードはここで受け入れられた回答にあります)。

AutoOpen については知りませんでしたが、同様の作業を行う必要があったため、次のような作業を行うレジストラントというクラスを作成しました。

type FSharpRegistrant() =
    do
        // do whatever I need to get going

次に、C# モジュール内の静的コンストラクターで、クラスを見つけるためにリフレクションを使用して F# 登録者をインスタンス化するコードをいくつか書きました (私のコード ベースでは C# コードが最初にビルドされ、F# コードが存在することをまったく知らないため)。これは多くのエラー チェックを伴う見苦しいコードですが、機能します。

于 2012-12-17T15:38:34.560 に答える