我有许多F#和C#项目的解决方案。我的目标是使用ILMerge将它们全部合并到一个库中。生成的合并dll将放在NuGet包中,并在其他项目中引用。但是,当在F#项目中引用合并的dll时,我遇到了一些问题。
我遇到的问题是,如果给予ILMerge的主要程序集是F#,那么在F#项目中引用结果dll只允许访问F#类型。如果选择C#dll作为合并的主程序集,则在F#项目中引用时,合并的F#程序集中的扩展方法不可用。此外,打开封闭命名空间时,不再隐式打开具有AutoOpen
属性的模块。
有没有办法合并F#和C#程序集,以便所有类型(包括扩展方法)都可用?
答案 0 :(得分: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#编译器中的一个错误,直到我们开始混淆混淆,我们需要在F#程序集上运行ildasm
并删除有问题的代码。另一个问题是F#没有正确支持成员上的protected修饰符(F#使它们公开),所以我们创建了一个属性,我们可以挂在要保护的类成员上。然后我们编写了一个工具,使用Cecil将程序集分开,删除我们的属性并将对这些成员的访问权限更改为protected(code is in the accepted answer here)。
我不知道AutoOpen,但我必须做类似的任务,所以我创建了一个名为注册人的类,就像这样做了这样的工作:
type FSharpRegistrant() =
do
// do whatever I need to get going
然后在C#模块中的静态构造函数中,我编写了一些代码,使用反射来实例化F#注册人以找到类(因为在我的代码库中,C#代码首先构建,并且根本不知道有F#代码) 。这是一个丑陋的代码,有很多错误检查,但它确实有用。