导致生成问题的 F# 程序集引用

本文关键字:程序集 引用 成问题 | 更新日期: 2023-09-27 18:32:52

我们有一个F#程序集(AssemblyOne(,它在单个Visual Studio 2012解决方案中引用另一个F#程序集(AssemblyTwo(。 AssemblyTwo引用了 C# DLL (MyCSharpLib (。

AssemblyOne 中定义的函数调用在 AssemblyTwo 中定义的函数:

namespace AssemblyOne
[<RequireQualifiedAccess>]
module MyModuleA =
    let FetchResult id =
        let result = AssemblyTwo.MyModuleC.FetchResult id
        result

AssemblyTwo中调用的函数调用同一程序集中的另一个函数(FetchActualResult()(,该程序集采用属于引用的 C# DLL (MyCSharpLibMyCSharpType 类型的参数:

namespace AssemblyTwo
[<RequireQualifiedAccess>]
module MyModuleB  =
    let FetchActualResult(myCSharpType:MyCSharpLib.MyCSharpType, id:int)
        //return a result
[<RequireQualifiedAccess>]
module MyModuleC =
    let FetchResult id =
        let myCSharpType = new MyCSharpLib.MyCSharpType()
        MyModuleB.FetchActualResult(myCSharpType, id)

该解决方案在 Visual Studio 中编译和生成;但是,当我们尝试使用 MSBuild 从命令行生成项目时,生成失败,并在 msbuild.log 中出现以下错误:

error FS0074: The type referenced through 'MyCSharpLib' is defined in an assembly that is not referenced. You must add a reference to assembly 'MyCSharpLib'.

AssemblyTwo FetchActualResult()函数签名中作为MyCSharpLib参数公开的类型似乎导致了错误。 AssemblyOne现在需要引用MyCSharpLib,即使AssemblyOne没有直接使用MyCSharpLib中的任何内容。如果我们从函数签名中删除参数,则解决方案构建时没有错误。

我们通过使用以下用例复制代码("->"表示程序集引用(进一步探讨了这个问题:

  • F# AssemblyOne -> F# AssemblyTwo -> MyCSharpLib (C# DLL( (不生成(
  • F# AssemblyOne -> F#
  • AssemblyTwo -> MyFSharpLib (F# DLL( (不生成(
  • F# AssemblyOne ->
  • F# AssemblyTwo -> C# AssemblyThree(同一解决方案中的程序集((不生成(
  • F# AssemblyOne -> F#
  • AssemblyTwo -> F# AssemblyThree(同一解决方案中的程序集((生成(

这种行为可以解释吗?

导致生成问题的 F# 程序集引用

假设您的源代码中存在拼写错误,正如 DWright 指出的那样,我想说此错误可能只是因为通过此代码定义了一个静态类 MyModuleB,其中包含外部类型 MyCsharpType 的公开方法参数。

这就是Fsharp代码转换为IL的方式(从ILSpy - 重新翻译成Csharp(:

...
public static class MyModuleB
{
    public static string FetchActualResult(MyCSharpType myCSharpType, int id)
    {
        return myCSharpType.Fetch(id);
    }
}

如果不公开类型以使其静态可见,则可能不会显示错误。但是,这将取决于编译器的实现。

我可以想象,在编译MyModuleA的过程中,编译过程的一个配置或编译器的版本可以尝试"触摸"MyModuleB,从而尝试达到未引用的参数类型,而其他配置可能只是不接触MyModuleB。这要看情况。

因此,在我看来,问题不在于编译过程,而在于您公开了未引用其程序集的类型。

我刚才用这种方式解决了类似的情况。试试这个。

在 MyModuleC 的末尾,添加以下行:

let fetchResult = FetchResult

然后,在 MyModuleA 中,调用 fetchResult 而不是 FetchResult。当然有论据。

是的,我知道这听起来很傻,但一定要尝试。我相信它会打破不需要的依赖。

如果按原样使用 C# 中的 AssemblyTwo,则可能不会遇到此问题。当您使用 F# 中的 AssemblyTwo 时,它会浮出水面,所以我想知道 F# 编译器是否存在问题,或者它可能与超出我的柯里格式有关。无论如何,我希望 F# 编译器更聪明。也许有人应该提出问题,除非它已经完成。