【问题标题】:Akka.NET can C# actors be created within F# system?Akka.NET 可以在 F# 系统中创建 C# 角色吗?
【发布时间】:2017-04-25 20:31:27
【问题描述】:

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

我在 F# API 页面中也找不到任何关于如何创建在 C# 库中定义的参与者的文档。这只是没有完成吗?它通常是一个“糟糕”的设计吗?即,演员系统应该在库本身内创建吗?

编辑:我在下面玩的代码

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# 脚本

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

【问题讨论】:

  • C# 和 F# 都编译为 IL。它应该与调用任何其他 F# 库没有什么不同,只要您提供正确的类型和参数等,一切都应该正常工作。
  • 你能发布类型签名,以及确切的错误信息。
  • 您可能需要将该函数转换为 C# 的适当委托类型
  • 根据 Akka.net 源代码(github.com/akkadotnet/akka.net/blob/dev/src/core/Akka/Actor/… 第 389 行),Props.Create() 将 LINQ 表达式<_> 作为其参数,似乎将 F# lambda 转换为表达式<_> 需要一些额外的步骤,您可以在网上轻松找到。
  • 它应该像问题中所写的那样工作;我试过了(相同的星座 - 在 C# 项目中定义并从 F# 使用的演员)并且没有得到任何错误。

标签: c# f# akka.net


【解决方案1】:

Props.Create with function 将不起作用,因为 C# 中的 Props.Create(() =&gt; new Actor(a, b)) 实际上是获取一个表达式,并将其解构为 actor 类型和构造函数参数。这是必要的,因为 Props 要求之一是它必须是可序列化的。

你可以做的是使用另一个重载Props.Create(typeof&lt;MyActor&gt;, [| box myArg1; box myArg2 |]),它基本上做同样的事情,只是没有编译类型安全。

话虽如此,如果可能的话,最好只使用AkklingAkka.FSharp API。

【讨论】:

    猜你喜欢
    • 2023-04-11
    • 2017-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多