Чтобы упростить мой сценарий, давайте предположим, что у меня есть этот простой код:
let someCondition = false
let SomeFuncThatThrows () =
async {
if someCondition then
raise <| InvalidOperationException()
return 0
}
let DoSomethingWithFoo (foo: int) =
Console.WriteLine (foo.ToString())
let SomeWrapper () =
async {
let! foo = SomeFuncThatThrows()
DoSomethingWithFoo foo
}
[<EntryPoint>]
let main argv =
Async.RunSynchronously (SomeWrapper ())
0
При его выполнении он, очевидно, просто печатает «0». Однако однажды обстоятельства меняются, и некоторый внешний фактор заставляет someCondition
становиться true
. Чтобы программа не взломала sh в этом сценарии, я хочу обработать исключение. Тогда для F # newb ie легко изменить SomeWrapper, добавив блок try-with, который, как многие думают, работает:
let SomeWrapper () =
async {
let! foo =
try
SomeFuncThatThrows()
with
| :? InvalidOperationException ->
Console.Error.WriteLine "aborted"
Environment.Exit 1
failwith "unreachable"
DoSomethingWithFoo foo
}
Однако это выше не работает (исключение по-прежнему необработанным), потому что SomeFuncThatThrows возвращает успешный результат: элемент Async<int>
. Исключением является бит let! foo =
, поскольку он ожидает рабочей нагрузки asyn c.
Однако, если вы хотите изменить SomeWrapper для исправления обработки исключения, многие могут подумать, что это возможно:
let SomeWrapper () =
async {
let foo =
try
let! fooAux = SomeFuncThatThrows()
fooAux
with
| :? InvalidOperationException ->
Console.Error.WriteLine "aborted"
Environment.Exit 1
failwith "unreachable"
DoSomethingWithFoo foo
}
Но нет, компилятор недоволен, так как он сообщает о следующей ошибке:
/ ... / Program.fs (17,17): Ошибка FS0750: эта конструкция может использоваться только в выражениях вычислений (FS0750) (SomeProject)
Тогда, кажется, единственный способ, которым я мог бы это исправить, таков:
let SomeWrapper () =
async {
try
let! foo = SomeFuncThatThrows()
DoSomethingWithFoo foo
with
| :? InvalidOperationException ->
Console.Error.WriteLine "aborted"
Environment.Exit 1
failwith "unreachable"
}
Однако я Я не на 100% доволен этим решением, потому что try-with слишком широк, так как он также охватывает вызов функции DoSomethingWithFoo, которую я хотел оставить за пределами блока try-with. Есть ли лучший способ исправить это без написания non-idiomati c F #? Должен ли я сообщать об ошибке компилятора как запрос функции в репозитории Microsoft F # GitHub?