简体   繁体   English

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

[英]Akka.NET can C# actors be created within F# system?

I'm trying to use some ReceiveActor s defined in a C# library within an F# system. 我正在尝试使用F#系统中C#库中定义的一些ReceiveActor I tried creating the non-F# API ActorSystem but the call to system.ActorOf(Props.Create(fun () -> new CSharpActor())) doesn't work saying the function argument is not compatible. 我尝试创建非F#API ActorSystem但是对system.ActorOf(Props.Create(fun () -> new CSharpActor()))的调用不起作用,说函数参数不兼容。

I also couldn't find any documentation in the F# API pages on how to create actors defined in a C# library. 我也在F#API页面中找不到有关如何创建在C#库中定义的actor的任何文档。 Is this just not done? 这不是吗? Is it generally a "bad" design - ie should the actor system be created within the library itself? 它通常是一个“坏”的设计 - 即演员系统应该在图书馆内创建吗?

EDIT : Code that I am playing with below 编辑 :我正在玩的代码如下

C# code 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 F#脚本

#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"

Props.Create with function won't work, because what Props.Create(() => new Actor(a, b)) in C# does is actually taking an expression, and deconstructing it into actor type and constructor arguments. Props.Create with function将不起作用,因为C#中的Props.Create(() => new Actor(a, b))实际上是一个表达式,并将其解构为actor类型和构造函数参数。 This is necessary, because one of the Props requirements is that it has to be serializable. 这是必要的,因为其中一个Props要求是它必须是可序列化的。

What you can do is to use another overload of Props.Create(typeof<MyActor>, [| box myArg1; box myArg2 |]) which essentially does the same, just without compile type safety. 你可以做的是使用Props.Create(typeof<MyActor>, [| box myArg1; box myArg2 |])另一个重载Props.Create(typeof<MyActor>, [| box myArg1; box myArg2 |])基本上做同样的Props.Create(typeof<MyActor>, [| box myArg1; box myArg2 |]) ,只是没有编译类型安全。

That being said, it'd be better if you'd just use Akkling or Akka.FSharp API when possible. 话虽这么说,如果你只是在可能的情况下使用AkklingAkka.FSharp API会更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM