2

这是我用来隔离问题的测试代码:

open Microsoft.FSharp.Metadata
[<EntryPoint>]
let main args =
  let core = FSharpAssembly.FromFile @"C:\Program Files\FSharp-2.0.0.0\\bin\FSharp.Core.dll"
  let core2 = FSharpAssembly.FSharpLibrary
  let core3 = System.AppDomain.CurrentDomain.GetAssemblies() 
              |> Seq.find (fun a -> a.FullName.Contains "Core") 
              |> FSharpAssembly.FromAssembly

  core.Entities |> Seq.iter (printfn "%A")
  0

所有三个lets 都应该给我相同的 FSharpAssembly。相反,所有 3 都抛出 FSharp.Core 不是 F# 程序集的异常(详情如下,为便于阅读重新格式化)。还有两个线索:

  1. 使用该core3方法,我得到了测试 F# 程序集本身的相同错误
  2. 做完后我在 FSI 没有收到错误#r "@C:\Program Files...\FSharp.Powerpack.Metadata.dll"

有任何想法吗?我在旧的 XP VM 上使用 Visual Studio 2008、F# 2.0 和 F# Powerpack 2.0.0.0(2010 年 5 月 20 日)版本,但我认为它已更新到 SP3。

(今天早上我收到了 Powerpack 1.9.9.9 的错误,所以我升级到 2.0.0.0。我认为如果 1.9.9.9 不能识别 F# 的 2.0.0.0 程序集,那么 Powerpack 2.0.0.0 中的错误修复可能会有所帮助.)

Unhandled Exception: System.TypeInitializationException: 
  The type initializer for 'Microsoft.FSharp.Metadata.AssemblyLoader' threw an
    exception. 
  ---> System.TypeInitializationException: The type initializer for
    '<StartupCode$FSharp-PowerPack-Metadata>.$Metadata' threw an exception. 
  ---> System.ArgumentException: could not produce an FSharpAssembly 
    object for the assembly 'FSharp.Core' because 
    this is not an F# assembly
Parameter name: name
   at Microsoft.FSharp.Metadata.AssemblyLoader.Add(String name,Assembly assembly)
   at <StartupCode$FSharp-PowerPack-Metadata>.$Metadata..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.FSharp.Metadata.AssemblyLoader..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.FSharp.Metadata.AssemblyLoader.Get(Assembly assembly)
   at Microsoft.FSharp.Metadata.FSharpAssembly.FromAssembly(Assembly assembly)
   at Program.main(String[] args) in 
     C:\Documents an...\FSMetadataTest\Program.fs:line 11
Press any key to continue . . .
4

3 回答 3

3

内森,很好的调查,2010 年 5 月的原始版本确实没有更新版本号,请参阅http://fsharppowerpack.codeplex.com/workitem/4548 我们已经上传了具有更正版本号的二进制文件。

于 2010-06-04T08:21:56.313 回答
3

通过阅读Codeplex 上的 Powerpack 源代码,我找到了问题的直接原因。Powerpack.Metadata 总是在任何其他程序集之前加载 FSharp.Core,因此如果它被破坏,它会阻止其余的程序集。

根据我的研究,大多数其他 F# 程序集在名为“ FSharpSignatureData.Package.Name ”的清单资源流中携带它们的元数据——这是元数据库首先出现的地方。但 FSharp.Core 没有。(至少,在我的 XP VM 上,VS 2008 的 2.0.0.0 下载没有。)因此,Powerpack 元数据在它期望找到 FSharp.Core.dll 的同一目录中查找名为 FSharp.Core.sigdata 的文件。

代码在四个位置查找此目录名称:

  1. ConfigurationSettings.AppSettings.["fsharp-core-referenceassembly-location"]。
  2. 注册表项@"SOFTWARE\Microsoft\.NETFramework\" + MSCorLibRunningRuntimeVersion + @"\AssemblyFoldersEx\Microsoft Visual F# 4.0",其中 MSCorLibRunningRuntimeVersion 由反射确定——在我的情况下,它是“v2.0.50727”。我认为这仅适用于您拥有 VS 2010 和 F# 4.0 的情况
  3. 注册表项@"Software\Microsoft\.NETFramework\AssemblyFolders\Microsoft.FSharp-" + FSharpTeamVersionNumber,其中 FSharpTeamVersionNumber 被硬编码为“1.9.9.9”,至少在 codeplex 版本中。我的机器上没有安装 2010 年 5 月版本的源代码。
  4. System.AppDomain.CurrentDomain.BaseDirectory。这是本地项目的“bin/Debug”目录,除非您在 fsi 中。然后是 C:\Program Files\FSharp-2.0.0.0\bin 的一些变体。

对我来说,所有四个都失败了:

  1. 我没有应用程序配置文件。我不太了解.NET 生态系统,所以我不知道如何创建一个。
  2. 我没有安装 VS 2010。
  3. 我在正确的位置有一个“Microsoft.FSharp-2.0.0.0”键,但没有“Microsoft.FSharp-1.9.9.9”键。
  4. 我的本地项目在 bin/Debug 目录中没有 FSharp.Core.sigdata 的副本。

现在我知道发生了什么,我有一些修复(除了使用真正的 Windows 机器而不是古老的虚拟机,我计划在大约一个月内修复它)。无论如何,我可能应该在某个时候了解 .NET 的配置文件,所以这可能是最好的中期解决方案。创建注册表项“Microsoft.FSharp-1.9.9.9”或将 FSharp.Core.sigdata 复制到 bin/Debug 目录是一个超级简单的短期修复。

我仍然不知道这个错误是否应该普遍存在,或者它是否只是由我从 VS 2005->2008 升级和多个 F# 预览引起的。通过阅读 codeplex 源,在我看来,其他没有 VS 2010 的人也应该有这个问题,只是因为 FSharpTeamVersionNumber 被硬编码为 1.9.9.9,并且尚未更新以匹配注册表项 2.0.0.0。但也许我升级到 F# 2.0 和 F# Powerpack 2.0 的顺序错误地混合在一起产生了这种情况。或者可能没有足够的人使用元数据库来暴露这个错误。

于 2010-06-01T16:59:38.407 回答
1

这真的很令人困惑 - 我尝试使用您描述的确切场景(Visual Studio 2008 中的 F# 2.0,使用 CodePlex 的最新 PowerPack 2.0)运行代码,并且它没有任何例外地工作。

您还可以确保您拥有最新版本的 F# for Visual Studio 2008(在 Visual Studio 2010 最终版本之后不久发布),因为FSharp.Core.dll您正在加载需要与FSharp.PowerPack.Metadata.dll. 此外,该Metadata库是否能够加载dll您使用当前版本的 F# 编译器编译的其他库?

编辑 如果这不起作用,那么(我认为)该Metadata库可能与 F# 编译器不同步:

let a = System.Reflection.Assembly.GetExecutingAssembly()
     |> FSharpAssembly.FromAssembly
printf "%A" a.Entities.Count

如果以下内容不起作用,那将非常令人困惑- 无论是什么版本,库都应该能够自行读取!

let a = FSharpAssembly.FromFile @"C:\...\bin\FSharp.PowerPack.Metadata.dll"
printf "%A" a.Entities.Count
于 2010-05-27T14:35:05.847 回答