Assembly.LoadFrom не работает, но только время от времени - PullRequest
1 голос
/ 07 февраля 2020

Я хочу написать программу, которая следит за изменениями .dll. Когда происходит изменение, он должен загрузить сборку и вызвать функцию foo внутри.

У меня есть код, который должен это реализовать, но он ведет себя странно. Иногда это работает. Иногда загружаемая сборка будет старой версией. Иногда он вызывает исключение BadImageFormatException.

Вот мой программный код (это F #, но я думаю, что это общий. NET Основной вопрос):

module HotReloadDemo

open System
open System.IO
open System.Reflection

[<EntryPoint>]
let main argv =
  let assemblyPath = argv.[0] // Path to the .dll to watch

  let mutable lastWriteTime = DateTime.MinValue

  while true do

    let writeTime =
      if File.Exists assemblyPath
      then
        File.GetLastWriteTimeUtc assemblyPath
      else
        lastWriteTime

    if writeTime > lastWriteTime
    then
      lastWriteTime <- writeTime

      try
        printfn "Last write time: %O " lastWriteTime

        printfn "Waiting for the build to finish (this is a hack)... "
        Threading.Thread.Sleep 10000 // 10s is plenty long enough for the build to finish

        printfn "Loading assembly path from: %s " assemblyPath

        let assembly = Assembly.LoadFrom assemblyPath

        printfn "Got assembly: %O" (assembly.GetName ())

        let foo : (Unit -> int) option =
          assembly.GetExportedTypes()
          |> Array.tryHead
          |> Option.bind (fun t -> t.GetMethod "foo" |> Option.ofObj)
          |> Option.map (fun m -> (fun () -> m.Invoke (null, Array.empty) :?> int))

        match foo with
        | Some foo ->
          printfn "foo () = %O" (foo ())
        | None ->
          printfn "foo not found"

      with exn ->
        printfn "%O" exn

    else
      ()

  Threading.Thread.Sleep 1000

  0

Тогда у меня есть очень простая библиотека, которую можно просмотреть в другой проект, подобный этому:

module HotReload

  let foo () =
    123456

Чтобы проверить его, я запускаю программу «наблюдатель». Он успешно загружается и вызывает foo.

Затем я изменяю свою библиотеку (например, чтобы вернуть другое число) и собираю ее с помощью dotnet build.

Наблюдатель обнаруживает изменение, загружает сборку снова и вызывает foo, но печатает номер до изменения!

Затем я изменяю библиотеку снова с другим номером. Он обнаруживает изменение, но вылетает:

...

Loading assembly path from: ../hot-reload-lib/bin/Debug/netstandard2.0/hot-reload-lib.dll 
System.BadImageFormatException: Could not load file or assembly '<Unknown>'. Index not found. (0x80131124)
File name: '<Unknown>'
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)

...

Что здесь происходит?


dotnet  --version 
3.0.100

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.3 LTS
Release:    18.04
Codename:   bionic
...