Как использовать Microsoft Coyote в коде F # - защищенный вложенный тип атрибута в родительском типе - PullRequest
3 голосов
/ 09 мая 2020

Есть ли здесь языковая разница между F # и C#, которая блокирует использование Microsoft Coyote из кода F #?

Поскольку OnEventDoActionAttribute определен в унаследованном типе Microsoft.Coyote.Actors.Actor с защищенным модификатор доступа, похоже, он по-прежнему доступен в унаследованных типах акторов в 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 ]

4 голосов
/ 10 мая 2020

Да, это было сделано для того, чтобы уменьшить загрязнение области видимости и гарантировать, что вы получите intellisense для этих типов только тогда, когда вы находитесь в допустимом месте для их использования в Visual Studio. Хотя классная идея создать пример F # ...

3 голосов
/ 09 мая 2020

К сожалению, они объявили, что атрибут должен быть protected sealed вложенным в Actor. Хотя F # не может объявить что-либо как protected, он может следовать за ограничением доступа - обычно люди вводят ограничение доступа по какой-либо причине.

Другой способ сделать это - иметь класс верхнего уровня, наследующий от Actor и реализовать клиентов как вложенные классы. Но F # также не поддерживает вложенные классы.

Я не вижу особых причин для его объявления protected, кроме загрязнения области видимости.

Вероятно, разветвление и изменение модификатора доступа - самый простой вариант прямо сейчас.

...