委托和回调函数的问题 - fsharp,Exchange Managed API

Problems with delegate and callback funcitons - fsharp, Exchange Managed API

以下代码适用于 lambda 函数:

// https://msdn.microsoft.com/en-us/library/office/dn567668.aspx#Create
#r "C:\Program Files\Microsoft\Exchange\Web Services.2\Microsoft.Exchange.WebServices.dll"

open Microsoft.Exchange.WebServices.Data
open System

let exchangeService emailAddress password = 
    let service = new ExchangeService(ExchangeVersion.Exchange2010_SP2)
    service.Credentials <- new WebCredentials(emailAddress,password) 
    service.AutodiscoverUrl(emailAddress, (fun (redirectionUrl:string) -> redirectionUrl.ToLower().StartsWith("https://") ) )
    service

但是当我将 AutodiscoverUrl 中使用的 lambda 绑定到一个名称时,我遇到了问题:

let x (redirectionUrl:string) = redirectionUrl.ToLower().StartsWith("https://")
service.AutodiscoverUrl(emailAddress, x)

Visual Studio 抱怨 "x"。

"This expression was expected to have type Microsoft.Exchange.WebServices.Autodiscover.AutodiscoverRedirectionUrlValidationCallback but here has type string -> bool"

请注意,这与上面的 lambda 函数具有相同的签名。使用 f# interactive 检查...

fun (redirectionUrl:string) -> redirectionUrl.ToLower().StartsWith("https://")
val it : redirectionUrl:string -> bool = <fun:clo@1>

let x (redirectionUrl:string) = redirectionUrl.ToLower().StartsWith("https://")
val x : redirectionUrl:string -> bool

我错过了什么?

当调用将委托作为参数的方法时,F# 允许您使用 lambda 函数调用它并自动将其转换为委托(这就是您的第一个版本有效的原因)。

我认为并非所有版本的 F# 都会自动将命名函数转换为委托,因此当您想将命名函数用作参数时,可以通过显式创建委托来实现。这意味着如果你想将函数 x 作为参数传递,你可以这样写:

service.AutodiscoverUrl(emailAddress, AutodiscoverRedirectionUrlValidationCallback (x))

在这种情况下,将其包装在一个简短的内联 lambda 函数中可能更短:

service.AutodiscoverUrl(emailAddress, fun arg -> x arg)

编辑: 在最新版本的 F# 中,从命名函数到委托的转换也应该有效——但我认为这取决于这是哪种委托,还有其他什么那里有重载,您使用的是哪个 F# 版本。以上应该总是有效。