如何使用F# 3.0类型提供程序生成与C#兼容、支持.Net 4.0的类型

10
我希望利用 F# 3.0 类型提供程序机制,基于弱类型数据源生成“强”类型。生成的类型必须可以从只安装了 .Net 4.0 而非 .Net 4.5 的 C# 客户端中访问。如果无法实现 .Net 4.0 兼容性,则我们无法在当前大型 ERP 项目中使用类型提供程序。
到目前为止,我已经成功创建了 MyGeneratedTypes.dll,按照 MSDN 上的 tutorial("Providing Generated Types" 部分)进行操作,使用了“ProvidedTypes-0.2.fs”中的 ProvidedTypeDefinition。 (为了使其工作,我不得不从“ProvidedTypeDefinition.ConvertToGenerated”方法中删除“File.Delete...”行)。
“MyGeneratedTypes.dll”的运行时版本是v4.0.30319,这是可以的(.Net 4.0的运行时)。我可以在C#/.Net 4.0应用程序中添加对“MyGeneratedTypes.dll”的引用,并且智能感知功能会按预期显示类型和成员。但是,当我尝试编译时,C#编译器失败并产生“警告MSB3258:无法解析主引用“MyGeneratedTypes”,因为它具有对.NET Framework程序集“FSharp.Core,Version=4.3.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a”的间接依赖项,该程序集具有比当前目标框架中的版本“4.0.0.0”更高的版本“4.3.0.0”。”
使用IL Spy查看后发现,“MyGeneratedTypes.dll”确实包含对FSharp.Core 4.3的引用,尽管此引用完全不必要。到目前为止,我还没有找到防止F#编译器将此引用放入生成的程序集中的方法。(我已经创建了一个纯.Net 4.0 C#程序集,并将其传递给ProvidedTypeDefinition的构造函数,但这没有影响)。

有没有人知道如何消除引用,或者这是否只是 F# 3.0 发布候选版的问题,在最终版本中将得到解决。

编辑

与 @Brian 的交谈已经导致了以下问题的“部分”解决方案:您可以通过直接从命令行调用 .Net 4.0 C# 编译器 (csc) 来编译引用 F# 3.0 生成类型的库的“纯 C#/.Net 4.0”客户端,但在 VS 2010 中编译或通过 MSBuild 命令行编译时不起作用。我怀疑这是由以下行为引起的:

  1. MyGeneratedTypes.dll是使用F#类型提供程序机制在VS 2012中生成的。
  2. 在生成过程中,自动插入对FSharp.Core 4.3的引用(即使不需要),而没有在依赖项的元数据中指定“SpecificVersion:true”。
  3. 一个在“.Net 4.5-free”系统上的VS 2010中的C#客户端引用了MyGeneratedTypes.dll。
  4. 当编译C#客户端时,MSBuild发现了MyGeneratedTypes.dll中间接引用到FSharp.Core 4.3。
  5. 由于间接引用存在“SpecificVersion:false”,MSBuild发出警告MSB3257,并拒绝将直接引用/r:“MyGeneratedTypes.dll”传递给C#编译器(csc)。(注意:MSBuild警告无法以任何方式被抑制。)
  6. C#编译器(csc)由MSBuild调用,没有/r:“MyGeneratedTypes.dll”。因此,它无法编译,并发出编译器错误CS0246:“找不到类型或命名空间名称'MyGeneratedTypes'(...)”。
据我所知,除非修改F#类型提供程序机制中的a)在生成的程序集中不需要对FSharp.Core 4.3的引用或b)包含带有元数据"SpecificVersion:true"的引用,否则我们将无法解决此问题。

2
我没有答案,但是我很好奇——如果您要从C#使用库,为什么要使用F#类型提供程序呢?您是否计划在将来转向F#?因为如果不是这样的话,使用CodeDOM或Roslyn可能是解决问题的更简单方法。我认为大多数类型提供程序的价值都体现在您从F#中使用它们时... - Tomas Petricek
@Tomas 我们在解决方案的非 UI 部分中使用 F# 作为附加语言,该解决方案主要由许多 C# 项目组成。我希望类型提供程序提供了一种简化的方式来创建 CLI 类型生成器(通过使用 F# 引用ProvidedTypeDefinition 的简化 API)。到目前为止,我喜欢我所看到的,但它不能与 C# 编译(还?)。多年来,我们一直在使用自制的生成器来生成 C# 源代码文件,这是一个麻烦的维护工作。如果类型提供程序不起作用,我将研究 CodeDom 和 Roslyn -- 感谢您的建议。 - Marc Sigrist
1个回答

6

只需在C#项目中添加对FSharp.Core 4.3.0.0的引用(或忽略警告)。 尽管有奇怪的编号约定,但FSharp.Core 4.3.0.0不依赖于.Net 4.5中的任何内容,它仅依赖于.Net 4.0。


我已经尝试过了。无论如何,C#编译器都会给出两个错误,说它在生成的程序集中找不到命名空间和类型,尽管两者在C# IntelliSense中完全可见(这只是在C#编码时没有问题,而在C#编译时有问题)。C#编译器唯一的其他消息是“内部F#引用”警告,根据您的答复,这是无害的。在IL Spy中,程序集看起来很正常,除了F#引用之外。如果内部F#引用不是问题的根本原因,我不知道还可能是什么... - Marc Sigrist
2
好的,分享实际的编译器错误信息会很有帮助。所以你的意思是说ildasm/ilspy看到这些公共类型出现在F#程序集中,但由于某种原因,C#编译器没有“看到”它们,即使该程序集已经在csc.exe命令行中被引用了“/r”? - Brian
顺便提一下,当我在Windows 7上的'C#/.Net 4.0'项目中添加'FSharp.Core 4.3'引用(未安装.Net 4.5),在VS 2010 IDE中该引用旁边会出现黄色感叹号,表示存在某种冲突。 - Marc Sigrist
此外,在 C# 客户端的配置文件中添加从旧 FSharp.core 版本到 FSharp.core 4.3 的绑定重定向也没有帮助。 - Marc Sigrist
我已经找到了一个“半个”解决方案:正如你正确预测的那样,当从命令行运行时,C#编译器可以成功地构建使用生成类型的F#库的C#客户端。即使在只安装了.Net 4.0的平台上,编译也会成功。为了运行客户端,必须存在FSharp.core.dll(v 4.3),即使生成的类型根本没有使用它。这只是一个“半个”解决方案,因为无法从VS 2010内部进行编译。我们不能要求所有开发人员停止在VS 2010中编译... - Marc Sigrist
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接