如何在 F# 代码中使用 Microsoft Coyote - 父类型中受保护的嵌套属性类型
How to use Microsoft Coyote in F# code - protected nested attribute type in parent type
这里 F# 和 C# 之间是否存在语言差异,阻止从 F# 代码使用 Microsoft Coyote?
因为 OnEventDoActionAttribute
是在具有受保护访问修饰符的继承类型 Microsoft.Coyote.Actors.Actor
中定义的,所以看起来它仍然可以在 C# 的继承 actor 类型中访问,但在 F# 中则不然。
Hello world 示例转换为 F#:
type SetupEvent(serverId : ActorId) =
inherit Event()
member this.ServerId = serverId
type PingEvent(callerId : ActorId) =
inherit Event()
member this.Caller = callerId
type PongEvent() =
inherit Event()
// both attribute spec fail
//[<Microsoft.Coyote.Actors.Actor.OnEventDoAction(typeof<PingEvent>, "HandlePing")>] // Error: The type 'OnEventDoActionAttribute' is not accessible from this code location
[<OnEventDoAction(typeof<PingEvent>, "HandlePing")>] // Error: The type 'OnEventDoAction' is not defined
type Server() =
inherit Actor()
member this.HandlePing(e : Event) =
let ping = e :?> PingEvent
printfn "Server handling ping"
printfn "Server sending pong back to caller"
this.SendEvent(ping.Caller, new PongEvent());
// both attribute spec fail
//[<Microsoft.Coyote.Actors.Actor.OnEventDoAction(typeof<PongEvent>, "HandlePong")>] // Error: The type 'OnEventDoActionAttribute' is not accessible from this code location
[<OnEventDoAction(typeof<PongEvent>, "HandlePong")>] // Error: The type 'OnEventDoAction' is not defined
type Client() =
inherit Actor()
let mutable serverId : ActorId = null
override this.OnInitializeAsync(initialEvent : Event) : System.Threading.Tasks.Task =
printfn "%A initializing" this.Id
serverId <- (initialEvent :?> SetupEvent).ServerId
printfn "%A sending ping event to server" this.Id
this.SendEvent(serverId, new PingEvent(this.Id))
base.OnInitializeAsync(initialEvent)
member this.HandlePong() =
printfn "%A received pong event" this.Id
[<Test>]
let Execute (runtime : IActorRuntime) =
let serverId = runtime.CreateActor(typeof<Server>)
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
let runtime = RuntimeFactory.Create()
Execute(runtime) |> ignore
Console.ReadLine() |> ignore
不确定如何解决此问题。
LINQPad文档URI直接试用代码:http://share.linqpad.net/a9rif7.linq
不幸的是,他们 declared 属性是 protected sealed
嵌套在 Actor
中。虽然 F# 不能将任何内容声明为 protected
,但它可以遵循访问限制——通常人们出于某种原因强制执行访问限制。
您可以这样做的另一种方法是拥有一个继承自 Actor
的顶级 class,并将客户端实现为嵌套的 classes。但是 F# 也不支持嵌套 classes。
除了范围污染之外,我看不出有任何特别的原因可以声明它 protected
。
可能分叉和更改访问修饰符是目前最简单的选择。
是的,它是为了减少作用域污染,并确保只有当您在 Visual Studio 中的有效位置使用这些类型时,才能获得这些类型的智能感知。不过构建 F# 示例的想法很酷...
这里 F# 和 C# 之间是否存在语言差异,阻止从 F# 代码使用 Microsoft Coyote?
因为 OnEventDoActionAttribute
是在具有受保护访问修饰符的继承类型 Microsoft.Coyote.Actors.Actor
中定义的,所以看起来它仍然可以在 C# 的继承 actor 类型中访问,但在 F# 中则不然。
Hello world 示例转换为 F#:
type SetupEvent(serverId : ActorId) =
inherit Event()
member this.ServerId = serverId
type PingEvent(callerId : ActorId) =
inherit Event()
member this.Caller = callerId
type PongEvent() =
inherit Event()
// both attribute spec fail
//[<Microsoft.Coyote.Actors.Actor.OnEventDoAction(typeof<PingEvent>, "HandlePing")>] // Error: The type 'OnEventDoActionAttribute' is not accessible from this code location
[<OnEventDoAction(typeof<PingEvent>, "HandlePing")>] // Error: The type 'OnEventDoAction' is not defined
type Server() =
inherit Actor()
member this.HandlePing(e : Event) =
let ping = e :?> PingEvent
printfn "Server handling ping"
printfn "Server sending pong back to caller"
this.SendEvent(ping.Caller, new PongEvent());
// both attribute spec fail
//[<Microsoft.Coyote.Actors.Actor.OnEventDoAction(typeof<PongEvent>, "HandlePong")>] // Error: The type 'OnEventDoActionAttribute' is not accessible from this code location
[<OnEventDoAction(typeof<PongEvent>, "HandlePong")>] // Error: The type 'OnEventDoAction' is not defined
type Client() =
inherit Actor()
let mutable serverId : ActorId = null
override this.OnInitializeAsync(initialEvent : Event) : System.Threading.Tasks.Task =
printfn "%A initializing" this.Id
serverId <- (initialEvent :?> SetupEvent).ServerId
printfn "%A sending ping event to server" this.Id
this.SendEvent(serverId, new PingEvent(this.Id))
base.OnInitializeAsync(initialEvent)
member this.HandlePong() =
printfn "%A received pong event" this.Id
[<Test>]
let Execute (runtime : IActorRuntime) =
let serverId = runtime.CreateActor(typeof<Server>)
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
runtime.CreateActor(typeof<Client>, new SetupEvent(serverId)) |> ignore
let runtime = RuntimeFactory.Create()
Execute(runtime) |> ignore
Console.ReadLine() |> ignore
不确定如何解决此问题。
LINQPad文档URI直接试用代码:http://share.linqpad.net/a9rif7.linq
不幸的是,他们 declared 属性是 protected sealed
嵌套在 Actor
中。虽然 F# 不能将任何内容声明为 protected
,但它可以遵循访问限制——通常人们出于某种原因强制执行访问限制。
您可以这样做的另一种方法是拥有一个继承自 Actor
的顶级 class,并将客户端实现为嵌套的 classes。但是 F# 也不支持嵌套 classes。
除了范围污染之外,我看不出有任何特别的原因可以声明它 protected
。
可能分叉和更改访问修饰符是目前最简单的选择。
是的,它是为了减少作用域污染,并确保只有当您在 Visual Studio 中的有效位置使用这些类型时,才能获得这些类型的智能感知。不过构建 F# 示例的想法很酷...