问题
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