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