Akka.NET可以在F#系统中创建C#actor吗?

时间:2017-04-25 20:31:27

标签: c# f# akka.net

我正在尝试使用F#系统中C#库中定义的一些ReceiveActor。我尝试创建非F#API ActorSystem但是对system.ActorOf(Props.Create(fun () -> new CSharpActor()))的调用不起作用,说函数参数不兼容。

我也在F#API页面中找不到有关如何创建在C#库中定义的actor的任何文档。这不是吗?它通常是一个“坏”的设计 - 即演员系统是否应该在图书馆内创建?

编辑:我正在玩的代码

C#代码

namespace CsActors {
  using Akka.Actor;
  using System;

  public class CsActor : ReceiveActor {
    public CsActor() {
      Receive<string>(msg => { Console.WriteLine($"C# actor received: {msg}"); });
    }
  }

  public class CsActorWithArgs : ReceiveActor {
    public CsActorWithArgs(string prefix) {
      Receive<string>(msg => { Console.WriteLine($"{prefix}: {msg}"); });
    }
  }
}

F#script

#I @"../build"

#r @"Akka.dll"
#r @"Akka.FSharp.dll"
#r @"CsActors.dll"

open Akka.Actor
open Akka.FSharp
open CsActors

let system = System.create "fcmixed" (Configuration.load())

// fails at runtime with "System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.NewExpression'."
//let c1 = system.ActorOf(Props.Create(fun _ -> CsActor()))

// works if CsActor has constructor with no arguments
let c2 = system.ActorOf<CsActor> "c2"
c2 <! "foo"

// if actor doesn't have default constructor - this won't compile
//let c3 = system.ActorOf<CsActorWithArgs> "c3"

// Horusiath solution works for actors requiring arguments
let c4 = system.ActorOf(Props.Create(typeof<CsActorWithArgs>, [| box "c4-prefix" |]))
c4 <! "foo"


// Just for fun trying to use suggestion by dumetrulo (couldn't quite get it to work...)
// copied Lambda module from http://www.fssnip.net/ts/title/F-lambda-to-C-LINQ-Expression
//module Lambda =
//    open Microsoft.FSharp.Linq.RuntimeHelpers
//    open System.Linq.Expressions
//    let toExpression (``f# lambda`` : Quotations.Expr<'a>) =
//        ``f# lambda``
//        |> LeafExpressionConverter.QuotationToExpression
//        |> unbox<Expression<'a>>
//let c5 = system.ActorOf(Props.Create(<@ (fun _ -> CsActorWithArgs "c5-prefix") @> |> Lambda.toExpression))
//c5 <! "foo"

1 个答案:

答案 0 :(得分:2)

带有函数的

Props.Create无法正常工作,因为C#中的Props.Create(() => new Actor(a, b))实际上是在接受一个表达式,并将其解构为actor类型和构造函数参数。这是必要的,因为其中一个道具要求是它必须是可序列化的。

你可以做的是使用Props.Create(typeof<MyActor>, [| box myArg1; box myArg2 |])的另一个重载,它实际上是相同的,只是没有编译类型安全。

话虽如此,如果您在可能的情况下使用AkklingAkka.FSharp API,情况会更好。