2015-10-23 108 views
3

我试图实现在F#接口(WCF的名声)IDispatchMessageInspector通过参考令行禁止参数传递参数

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 

这失败,出现以下错误编译:

enter image description here

但是,如果我将我的代码修改为以下内容(请注意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) 

预计这种行为?如果是的话,有人可以解释它背后的原因......

+1

不知道它会帮助;当试验时,我尝试使用'(ref arg)'而不是使用'&arg',并且我得到了这个错误:*错误FS0440:带有curried参数的方法不能声明(...)或'byref'参数*因此它可能是预期的行为;为什么现在我不知道。 – Sehnsucht

回答

7

原因是,在.NET中byref<'T>不是真正的类型。 F#使用它来表示通过refout参数传递的值,但它不是可以出现在程序中任何位置的正常类型。 F#限制了它们可以使用的范围 - 你只能用它们作为局部变量(基本上是传递一个引用或指针),你可以将它们用作方法参数(编译器可以将它编译为一个方法参数)。

使用curried方法,编译器正在生成返回函数值的属性,所以(在封面下),您得到类似FSharpFunc<T1, FSharpFunc<T2, T3>>类型的属性PostInvoke。在这里,T1T2不能是byref<T>类型,因为byref不是真正的.NET类型。所以这就是为什么咖喱方法不能有byref参数。

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

let foo() = 
    let a : list<byref<int>> = [] 
    a 

这里:

error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

+0

感谢澄清托马斯 - 观察'byref <'T>'不是一种类型突然说清楚 - 谢谢! – Lawrence

+0

也许值得一提的是,即使是异常消息也不能识别你的观察:“..但是这里有'byref <'a>'......”类型! – Lawrence

+0

是的,我认为F#编译器将它视为类型检查期间的一种类型,但在代码生成期间将其擦除 - 所以它是假类型:)(以某种方式,“System.Void”的行为类似......它看起来像一种类型,但不能创建空洞列表......) –