Метаданные F# Powerpack не распознают FSharp.Core как библиотеку F#

Вот мой тестовый код, чтобы изолировать проблему:

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",

Есть идеи? Я использую Visual Studio 2008, F# 2.0 и F# Powerpack 2.0.0.0 (20 мая 2010 г.) на старой версии виртуальной машины XP, но думаю, что она обновлена ​​до 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 . . .

3 ответа

Решение

Натан, большое расследование, номер версии действительно не обновлялся в оригинальном выпуске за май 2010 года, см. http://fsharppowerpack.codeplex.com/workitem/4548 Мы загрузили двоичные файлы с исправленным номером версии.

Я нашел непосредственную причину проблемы, читая источник Powerpack на Codeplex. Powerpack.Metadata всегда загружает FSharp.Core перед любой другой сборкой, поэтому, если она сломана, она блокирует все остальное.

По моим исследованиям, большинство других сборок F# переносят свои метаданные с собой в поток ресурсов манифеста с именем "FSharpSignatureData.Package.Name" - вот где библиотека метаданных смотрится первой. Но FSharp.Core не делает. (По крайней мере, на моей виртуальной машине XP загрузка 2.0.0.0 для VS 2008 этого не делает.) Таким образом, метаданные Powerpack ищут файл с именем FSharp.Core.sigdata в том же каталоге, в котором он ожидает найти файл FSharp.Core.dll.

Код ищет четыре места для этого имени каталога:

  1. ConfigurationSettings.AppSettings. [ "FSharp-ядро-referenceassembly-место"].
  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 года.
  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. В моем локальном проекте нет копии FSharp.Core.sigdata в каталоге bin/Debug.

Теперь, когда я знаю, что происходит, у меня есть ряд исправлений (помимо использования реальной машины с 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, был неправильно смешан, чтобы вызвать это условие. Или, может быть, недостаточно людей, использующих библиотеку метаданных, чтобы выявить ошибку.

Это действительно сбивает с толку - я попытался запустить код, используя точный сценарий, который вы описали (F# 2.0 в Visual Studio 2008, с последней версией PowerPack 2.0 от CodePlex), и он работает без каких-либо исключений.

Вы также можете убедиться, что у вас установлена ​​последняя версия F# для 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
Другие вопросы по тегам