为什么在从PowerShell调用F#代码时收到MissingMethodException?

问题描述:

我想使用PowerShell调用一些使用Akka.Net actor的F#代码。为什么在从PowerShell调用F#代码时收到MissingMethodException?

的F#代码工作正常的单元测试,并从F#解释器中运行时,但是当我把相同的代码从PowerShell命令我得到以下异常:

System.MissingMethodException: Method not found: 'Void Nessos.FsPickler.BinarySerializer..ctor(Microsoft.FSharp.Core.FSharpOption`1<Boolean>, 
        Microsoft.FSharp.Core.FSharpOption`1<Nessos.FsPickler.ITypeNameConverter>)'. 
         at Akka.FSharp.Serialization.ExprSerializer..ctor(ExtendedActorSystem system) 
         at Akka.FSharp.Serialization.exprSerializationSupport(ActorSystem system) 
         at Namespace.NewActorCmdlet..ctor(Host hostA, Host hostB, Boolean option, UserDetails user) in 
        E:\Projects\Namespace\NewActorCommand.fs:line 24 
         at Namespace.StartNewActorCommand.ProcessRecord() in 
        E:\Projects\Namespace\StartNewActor.fs:line 67 
         at System.Management.Automation.CommandProcessor.ProcessRecord() 

我试图在运行[Nessos.FsPickler.BinarySerializer]::new.OverloadDefinitions PowerShell会话检查什么方法PS虽然空出来了,我得到:

Nessos.FsPickler.BinarySerializer new(Microsoft.FSharp.Core.FSharpOption[bool] forceLittleEndian, Microsoft.FSharp.Core.FSharpOption[Nessos.FsPickler.ITypeNameConverter] typeConverter) 

我注意到的第一件事是,通过PowerShell中显示的版本需要一个FSharpOption [布尔]而不是FSharpOption [布尔]。我尝试修改Akka.FSharp代码以显式传递选项,但这似乎没有帮助。

我使用FSharp.Core 4.0.0.1(其他链接建议3.0有问题)。

有没有人见过类似的东西?

甚至有关在哪里寻找问题的建议都会有所帮助,我不确定问题出在PowerShell,F#或Akka.Net上。

+4

根据我的经验'MissingMethodException'总是由版本问题引起的。您的PowerShell会话很可能最终会加载一个不同于您的代码最初编译的程序集版本。你最好的选择是使用fuslogvw解决程序集绑定问题https://msdn.microsoft.com/en-us/library/e74a18c4 –

+0

fuslogvw原来是一个好的开始。没有解决问题,但让我至少诊断一下。 原来,Akka.FSharp和FsPickler是针对不同版本的FSharp.Core构建的。在常规项目中,您可以使用绑定重定向的魔术来掩盖这些差异,但在PowerShell中这不是那么容易。 最后我遵循@ user2470798和的建议放弃了重新设计的东西,所以我不直接从PowerShell调用Akka。 –

当涉及到基于参数类型的匹配方法时,Powershell会很困难。我发现有时我必须通过向表达式传递一个方法而不是PS变量来“欺骗”PS。例如$object.method($something.property)而不是$prop = $something.property; $object.method($prop)已经为我工作。

在重载方法的情况下,您可以做的另一件事是使用反射来确保您拥有正确签名的方法。例如:

$mi=$object.gettype().getmethod('TheMethod',@([typeParm1],[typeParm2])) 
$mi.invoke($object, @($arg1,$arg2)) 

有时铸造帮助:$object.method([typeToMatchMethodSig]$arg1)或者甚至一个双投:$object.method([bool][int]$arg1)在这两种情况下,我认为你有更多的运气,如果你通过投表达式作为参数,而不是将其分配到一个变量并传递变量。

我怀疑这是OP的情况,但使用[activator] :: createinstance(...)可以与私有构造函数一起使用。

我通常会把它弄糊涂,直到有些东西能奏效,或者我放弃。

顺便说一句,你可以打开PS跟踪参数绑定,并获得大量的信息,这可能会或可能不会有用。