Как использовать Microsoft Coyote в коде F# - защищенный вложенный тип атрибута в родительском типе
Есть ли здесь языковая разница между F# и C#, которая блокирует использование Microsoft Coyote из кода F#?
Поскольку OnEventDoActionAttribute
определен в унаследованном типе Microsoft.Coyote.Actors.Actor
с модификатором доступа protected похоже, что он все еще доступен в унаследованных типах акторов в C#, но не в 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
Не уверен, что делать, чтобы обойти эту проблему.
URI документа LINQPad для непосредственного опробования кода: http://share.linqpad.net/a9rif7.linq
2 ответа
К сожалению, они объявили атрибутprotected sealed
вложен внутрь Actor
. Хотя F# не может ничего объявить какprotected
, он может следовать за ограничением доступа - обычно люди вводят ограничение доступа по какой-то причине.
Другой способ сделать это - создать класс верхнего уровня, наследующий от Actor
и реализовать клиентов как вложенные классы. Но F# также не поддерживает вложенные классы.
Я не вижу особых причин для его объявления protected
кроме загрязнения области.
Вероятно, разветвление и изменение модификатора доступа сейчас самый простой вариант.
Да, это было сделано для того, чтобы уменьшить загрязнение области и гарантировать, что вы получаете intellisense для этих типов только тогда, когда вы находитесь в допустимом месте для их использования в Visual Studio. Хотя классная идея создать пример на F#...