What is the correct way to return an “empty task” when implementing message handlers such as IExceptionHandler or IExceptionLogger in F#?

霸气de小男生 提交于 2019-12-12 12:31:47

问题


In C# when implementing these handlers I would do something similar to this,

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

        return Task.FromResult(0);
    }
}

When implementing the same interface in F# I did the following,

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

The compiler was requiring the cast Task.FromResult(0) :> Task which is not required in the C# example. What is the correct and idiomatic way to return from the ExecuteAsync method in F#?


回答1:


The F# compiler requires a cast, because in F# there is no automatic conversion to supertypes (or to anything else for that matter). This is a very useful feature of F#, it guards against a whole class of mistakes, where conversion to supertype would change the meaning of the program.

So having this cast operator in your program is completely fine. If you don't feel like typing too much, you can also ask the compiler to infer the type for you:

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

If you really want to do away with the cast, you can use a task-creating method that returns a Task right away, instead of Task<T>, which would need to be cast. One such method is Task.Run( Action ):

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

But this is way more wasteful.



来源:https://stackoverflow.com/questions/36699555/what-is-the-correct-way-to-return-an-empty-task-when-implementing-message-hand

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!