簡體   English   中英

使用C#庫中的Akka.Net actor調用F#庫會導致TypeInitializationException

[英]Calling F# Library with Akka.Net actors from C# library leads to TypeInitializationException

我在我的測試解決方案中有3個項目:

  • f#類庫(讓我們把它命名為F#Lib),
  • f#console應用程序(讓我們將其命名為F#Console)和
  • c#console應用程序(C#Console)。

在類庫中我定義了一個akka.net actor:

namespace Just.Test.Project

open Akka.Actor
open Akka.FSharp
open Akka.Configuration

module Actors =

    let system = System.create "WaveNetSystem" (Configuration.defaultConfig())

    let simple = spawn system "simple" (fun mailbox ->
        let rec loop() = actor {
            let! message = mailbox.Receive()
            printfn "%A" message
            return! loop()
        }
        loop()
    )

type MainClass(msg) = let x = Actors.simple <! msg

如果我從f#console應用程序實例化MainClass ,我得到預期的結果:

[<EntryPoint>]
let main argv = 
    Just.Test.Project.MainClass("bugaga!") |> ignore
    System.Threading.Thread.Sleep(1000)
    0 // return an integer exit code

輸出:

"bugaga!!!"

但。 如果我從c#console app做同樣的事情:

static void Main(string[] args)
{
    new Just.Test.Project.MainClass("bugaga!");
    System.Threading.Thread.Sleep(1000);
}

我得到一個例外:

System.TypeInitializationException: The type initializer for '<StartupCode$SampleFSharpAkkaNet>.$Test' threw an exception. ---> System.MissingMethodException: Method not found: 'Akka.Actor.IActorRef  Akka.FSharp.Spawn.spawn(Akka.Actor.IActorRefFactory, System.String, Microsoft.FSharp.Core.FSharpFunc`2<Actor`1<!!0>,Cont`2<!!0,!!1>>)'.
   at <StartupCode$SampleFSharpAkkaNet>.$Test..cctor()
   --- End of inner exception stack trace ---
   at Just.Test.Project.Actors.get_simple()
   at Just.Test.Project.MainClass..ctor() in d:\prj\research\AkkaFSharpTest\SampleFSharpAkkaNet\Test.fs:line 20

我該如何解釋這個例外? 可能有什么問題?

UPDATE

正如在評論和Tomas Petricek的回答中已經指出的那樣,該問題與版本不匹配有關。 bindingRedirect完成工作,一切都開始工作。 但我仍然有一些誤解。

第一。 Akka.FSharp引用FSharp.Core 4.3.1

第二。 F#Lib和F#控制台引用FSharp.Core 4.4.0和C#Console根本沒有對FSharp.Core引用。

第三。 F#控制台就像一個魅力,如果我打印加載的程序集,我得到:

FSharpConsole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
FSharpLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Akka, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null
Akka.FSharp, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null

FsPickler, Version=1.2.21.0, Culture=neutral, PublicKeyToken=null
System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

所以,沒有FSharp.Core 4.3.1.0加載,一切都是tip-top!

第四。 C#控制台不起作用。 加載的程序集列表看起來有點奇怪:

CSharpConsole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
FSharpLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
FSharp.Core, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Akka, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null
Akka.FSharp, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null

這意味着FSharp.Core, Version=4.4.0.0FSharp.Core, Version=4.4.0.0FSharp.Core, Version=4.3.1.0 為什么? 為什么在F#Console案件中沒有發生這種情況?

問題(通常))在我腦海里。

首先,我從未研究過最終的F#Console配置。 最初的app.config非常簡單:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

但是在構建之后(由於AutoGenerateBindingRedirects MSBuild標志 )得到了所需的buinding重定向:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

第二個。 C#編譯器試圖通過在構建輸出中編寫這樣的消息來通知我這個問題:

無法解決“FSharp.Core,Version = 4.3.1.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”和“FSharp.Core,Version = 4.3.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”之間的沖突。 任意選擇“FSharp.Core,Version = 4.3.1.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”。 考慮從版本“4.3.1.0”[C:\\ Program Files(x86)\\ Reference Assemblies \\ Microsoft \\ FSharp.NETFramework \\ v4.0 \\的app.config重新映射程序集“FSharp.Core,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a” 4.3.1.0 \\ FSharp.Core.dll]到版本“4.4.0.0”[C:\\ Program Files(x86)\\ Reference Assemblies \\ Microsoft \\ FSharp.NETFramework \\ v4.0 \\ 4.4.0.0 \\ FSharp.Core.dll]解決沖突,擺脫警告。 C:\\ Program Files(x86)\\ MSBuild \\ 14.0 \\ bin \\ Microsoft.Common.CurrentVersion.targets(1820,5):警告MSB3276:發現同一依賴程序集的不同版本之間存在沖突。 請在項目文件中將“AutoGenerateBindingRedirects”屬性設置為true。 有關詳細信息,請參閱http://go.microsoft.com/fwlink/?LinkId=294190

但我認為C#編譯器只是比F#編譯器更具限制性。 我不知道在F#項目中,標志是自動設置的。 什么阻止我檢查它? 我不知道!

這聽起來像FSharp.Core.dll版本不匹配問題。

最有可能的是,您引用的是較新版本的FSharp.Core.dll不是由Akka.net的F#包裝器庫引用的版本。 您可以引用相同的版本,也可以使用bindingRedirect添加配置文件。 請參閱Mark Seemann的博客文章

這里的關鍵字是MethodMissingException - 你得到的是因為方法的簽名涉及來自FSharp.Core.dll類型,並且已加載的版本(基於C#項目中的引用)與包裝器公開的版本不匹配(基於編譯包裝器時使用的引用)。 由於版本不匹配,類型被視為不同,並且“找不到方法”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM