5

我有许多 F# 和 C# 项目的解决方案。我的目标是使用 ILMerge 将它们全部合并到一个库中。生成的合并 dll 将放入 NuGet 包并在其他项目中引用。但是,当 F# 项目中引用合并的 dll 时,我遇到了一些问题。

我遇到的问题是,如果提供给 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# 程序集上运行并删除有问题的代码。另一个问题是 F# 没有正确支持成员上的 protected 修饰符(F# 将它们公开),因此我们创建了一个属性,我们可以将其挂在本应受保护的类成员上。然后我们编写了一个工具,使用 Cecil 将程序集拆开,删除我们的属性并将对这些成员的访问更改为受保护(代码在此处接受的答案中)。

我不知道 AutoOpen,但我必须做类似的任务,所以我创建了一个名为 registrant 的类,它可以像这样完成这样的工作:

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

然后在 C# 模块中的静态构造函数中,我编写了一些代码,使用反射来实例化 F# 注册者以查找类(因为在我的代码库中,C# 代码首先构建并且根本不知道有 F# 代码)。这是带有大量错误检查的丑陋代码,但它可以工作。

于 2012-12-17T15:38:34.560 回答