Why am I getting a MissingMethodException when cal

2019-07-12 02:27发布

I'm trying to use PowerShell to call some F# code which uses Akka.Net actors.

The F# code works fine in unit testing and when run from the F# interpreter, but when I call the same code from a PowerShell cmdlet I get the following exception:

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()

I tried running [Nessos.FsPickler.BinarySerializer]::new.OverloadDefinitions in that PowerShell session to check what methods PS though was available and I get:

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

First thing I noticed was that the version shown by PowerShell takes an FSharpOption[bool] instead of FSharpOption[Boolean]. I tried modifying the Akka.FSharp code to explcitly pass an Option, but that didn't seem to help.

I'm using FSharp.Core 4.0.0.1 (other links suggested 3.0 had problems).

Has anyone seen anything similar?

Even suggestions about where to look for the problem would be helpful, I'm not sure if the issue is with PowerShell, F# or Akka.Net.

1条回答
孤傲高冷的网名
2楼-- · 2019-07-12 02:48

Powershell can be difficult when it comes to matching methods based on parameter types. I've found that sometimes i have to "trick" PS by passing an expression to a method rather than a PS variable. For example $object.method($something.property) instead of $prop = $something.property; $object.method($prop) has worked for me.

In the case of overloaded methods another thing you can do is use Reflection to make sure you've got the method with the right signature. For example:

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

And sometimes casting helps: $object.method([typeToMatchMethodSig]$arg1) or maybe even a double cast:$object.method([bool][int]$arg1) In both cases I think you'll have more luck if you pass the cast expression as an argument, rather than assign it to a variable and pass the variable.

I doubt this is the case in the OP, but using [activator]::createinstance(...) can be used with a private constructor.

I usually muck around with it till either something works or I give up.

BTW, you can turn on PS tracing for parameter binding and get a lot of info, which may or may not be useful.

查看更多
登录 后发表回答