在curried的参数中通过引用传递参数

Law*_*nce 3 f#

我正在尝试IDispatchMessageInspector在F#中实现(WCF名声)界面:

open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels

type ServiceInterceptor() as interceptor = 

    abstract member PreInvoke : byref<Message> -> obj
    abstract member PostInvoke : byref<Message> -> obj -> unit

    default x.PreInvoke m = null
    default x.PostInvoke m s = ()

    interface IDispatchMessageInspector with
         member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
         member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke &reply correlationState
Run Code Online (Sandbox Code Playgroud)

无法编译时出现以下错误:

在此输入图像描述

但是,如果我将代码修改为以下内容(请注意签名的更改PostInvoke),一切正常:

open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels

type ServiceInterceptor() as interceptor = 

    abstract member PreInvoke : byref<Message> -> obj
    abstract member PostInvoke : byref<Message> * obj -> unit

    default x.PreInvoke m = null
    default x.PostInvoke (m, s) = ()

    interface IDispatchMessageInspector with
         member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
         member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke(&reply, correlationState)
Run Code Online (Sandbox Code Playgroud)

这种行为有望吗?如果是这样,有人可以解释它背后的推理......

Tom*_*cek 7

原因是它byref<'T>不是.NET中的真正类型.F#使用它来表示通过refout参数传递的值,但它不是可以出现在程序中任何位置的普通类型.

F#限制了它们的使用范围 - 你只能将它们用于局部变量(基本上传递一个引用或指针),你可以将它们用作方法参数(然后编译器可以将它编译为方法参数) .

使用curried方法,编译器会生成一个返回函数值的属性,因此(在封面下),您可以获得类似属性PostInvoke的内容FSharpFunc<T1, FSharpFunc<T2, T3>>.在这里,T1或者T2不能是byref<T>类型,因为byref它不是真正的.NET类型.这就是为什么curried方法不能有byref参数.

您可以看到这种情况的另一种情况是,例如,您是否尝试创建byref值列表:

let foo () =
  let a : list<byref<int>> = []
  a
Run Code Online (Sandbox Code Playgroud)

在这里你得到:

错误FS0412:类型实例化涉及byref类型.Common IL的规则不允许这样做.