在 F# 中实现消息处理程序(如 IExceptionHandler 或 IExceptionLogger)时返回"empty task"的正确方法是什么?



在C#中,当实现这些处理程序时,我会做类似的事情,

public class DefaultExceptionHandler : IExceptionHandler
{
    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        context.Result = new ErrorActionResult(context.Request, context.Exception);
        return Task.FromResult(0);
    }
}

当在F#中实现相同的接口时,我做了以下操作,

type DefaultExceptionHandler() =
    let mapExceptionTypetoHttpStatusCode (ex:Exception) : HttpStatusCode =
        match ex with
        | :? ArgumentException -> HttpStatusCode.BadRequest
        | _ -> HttpStatusCode.InternalServerError
    interface IExceptionHandler with
        member x.HandleAsync (context:ExceptionHandlerContext, cancellationToken:CancellationToken) =
            let request = context.Request
            let ex = context.Exception
            let httpStatusCode = mapExceptionTypetoHttpStatusCode ex
            context.Result <- { new IHttpActionResult with member x.ExecuteAsync(token:CancellationToken) = Task.FromResult(request.CreateErrorResponse(httpStatusCode, ex)) }
            Task.FromResult(0) :> Task

编译器需要转换Task.FromResult(0) :> Task,而C#示例中不需要该转换。从F#中的ExecuteAsync方法返回的正确且惯用的方法是什么?

F#编译器需要强制转换,因为在F#中没有自动转换到超类型(或其他任何类型)。这是F#的一个非常有用的功能,它可以防止一整类错误,即转换为超类型会改变程序的含义。

所以在你的程序中有这个cast操作符是完全可以的。如果你不想键入太多,你也可以让编译器为你推断类型:

let a: obj = "abcd"          // No cast - compile-time error
let b: obj = "abcd" :> obj   // Explicit cast to supertype
let c: obj = "abcd" :> _     // Explicit cast to inferred supertype

如果您真的想取消强制转换,可以使用一个任务创建方法,该方法立即返回Task,而不是需要强制转换的Task<T>。一种这样的方法是Task.Run( Action ):

let t = Task.Run( fun() -> () )   // t: Task

但这更浪费。

最新更新