【问题标题】:What is a standard type event for F#?什么是 F# 的标准类型事件?
【发布时间】:2020-03-03 08:46:12
【问题描述】:

我正在尝试从 F# 订阅/取消订阅 C# 制作的(在 RabbitMQ 客户端库中):

AsyncEventingBasicConsumer.cs

public event AsyncEventHandler<BasicDeliverEventArgs> Received;

AsyncEventHandler.cs

public delegate Task AsyncEventHandler<in TEvent>(object sender, TEvent @event) where TEvent : EventArgs;

我设法通过以下方式订阅了该活动:

let subscribeAsync (channel: IModel) exchange callback =
    let consumer = AsyncEventingBasicConsumer(channel)
    consumer.add_Received(AsyncEventHandler<BasicDeliverEventArgs>(fun sender args -> Task.CompletedTask))
    // ...

话虽如此,我想知道为什么下面的代码无法编译:

let subscribeAsync (channel: IModel) exchange callback =
    let consumer = AsyncEventingBasicConsumer(channel)
    consumer.Received.AddHandler(AsyncEventHandler<BasicDeliverEventArgs>(fun sender args -> Task.CompletedTask))
    // ...

因为我收到以下错误:

Program.fs(10, 14): [FS1091] The event 'Received' has a non-standard type. If this event is declared in another CLI language, you may need to access this event using the explicit add_Received and remove_Received methods for the event. If this event is declared in F#, make the type of the event an instantiation of either 'IDelegateEvent<_>' or 'IEvent<_,_>'.

我检查了the official MS documentation,但看不到任何关于 F# 标准事件类型的参考。

【问题讨论】:

    标签: c# .net-core f# rabbitmq event-handling


    【解决方案1】:

    F# 会将 .NET 事件公开为 IEventIDelegateEvent 类型的值,具体取决于事件声明和委托类型的外观。这只能针对具有一些基本通用结构的事件执行 - 当 F# 无法执行此操作时,它会将事件的底层 addremove 操作公开为您可以直接调用的方法。

    我不确定什么是“标准事件类型”的规则是什么。不过,你可以从the relevant bit of the F# compiler source code得到一些提示:

    let TryDestStandardDelegateType (infoReader: InfoReader) m ad delTy =
        let g = infoReader.g
        let (SigOfFunctionForDelegate(_, compiledViewOfDelArgTys, delRetTy, _)) =
            GetSigOfFunctionForDelegate infoReader delTy m ad
        match compiledViewOfDelArgTys with 
        | senderTy :: argTys when (isObjTy g senderTy) && 
             not (List.exists (isByrefTy g) argTys)  -> Some(mkRefTupledTy g argTys, delRetTy)
        | _ -> None
    

    所以,我的猜测是“标准事件类型”需要:

    • 至少有一个参数
    • 第一个参数的类型必须为object
    • 没有byref参数

    【讨论】:

    • 有道理,我开始深入研究编译器,但我花了一段时间才找到正确的地方。谢谢托马斯!
    猜你喜欢
    • 2021-10-30
    • 2021-03-26
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    • 2012-03-30
    相关资源
    最近更新 更多