F#的标准类型事件是什么?

时间:2020-03-03 08:46:12

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

我正在尝试从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#的标准事件类型的引用。

1 个答案:

答案 0 :(得分:2)

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参数