【问题标题】:F# assembly references causing build issues?F# 程序集引用导致构建问题?
【发布时间】:2016-05-09 19:00:21
【问题描述】:

我们有一个 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 (MyCSharpLib) 的 MyCSharpType 类型参数:

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(在同一解决方案中组装)(构建)

可以解释这种行为吗?

【问题讨论】:

  • 我不确定是什么原因造成的,但您可以检查的通常情况是 (1) 它们是否都引用了相同版本的 FSharp.Core.dll? (2) 它们是为同一个目标框架编译的吗?
  • (1) 它们都引用了相同版本的FSharp.Core.dll - 版本 4.3.0.0 和 (2) 所有程序集目标框架 v4.5
  • 您确定您使用的是与 VS 相同的 MSBuild 版本吗?您能在某处发布完整的 MSBuild 日志吗?
  • 两者都在使用 ToolsVersion="4.0"。
  • VS 和 msbuild 都可以使用 VS2013 编译程序集。

标签: c# visual-studio-2012 f# msbuild


【解决方案1】:

我刚刚以这种方式解决了一个类似的案例。试试这个。

在 MyModuleC 的末尾,添加这一行:

let fetchResult = FetchResult

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

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

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

【讨论】:

    【解决方案2】:

    假设正如 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。这取决于。

    所以在我看来,问题不在于编译过程,而事实上,您公开了一种类型的使用,而您没有引用它的程序集。

    【讨论】:

      猜你喜欢
      • 2017-03-14
      • 2011-04-03
      • 1970-01-01
      • 2017-07-29
      • 2011-04-20
      • 2013-04-25
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      相关资源
      最近更新 更多