2

I would like to translate the C# method DelayNe below to an F# function in such a way that it can be used from C# in exactly the same way. The reason is that I want to put it in an F# library. I am struggling a lot trying to google my way to an answer, with no luck obviously.

Update: Sorry for not being clear. I have tasks that call Task.Delay in the way that you see in the DelayNe method below. The problem is that when _cancellationTokenSource.Cancel() is called, then Task.Delay throws an exception, and I don't want that exception. In other words, I believe I need a wrapper around Task.Delay which will catch the exception and silence it, but otherwise expose the behavior of Task.Delay exactly as is. And I want to implement the wrapper in F#.

private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
async Task DelayNe(int milliSeconds, CancellationToken token)
{
 try
 {
 await Task.Delay(milliSeconds, token);
 }
 catch (TaskCanceledException ex)
 {
 ("Silencing " + ex.GetType().Name + ", " + ex.Message).Dump();
 }
}
async Task Test(CancellationToken cancellationToken)
{
 try
 {
 "Test start".Dump();
 await DelayNe(5000, cancellationToken);
 "Test stop".Dump();
 }
 catch (Exception ex)
 {
 ("Catch: " + ex.Message + ", " + ex.GetType().Name).Dump();
 }
}
async Task Main()
{
 "Start".Dump();
 _cancellationTokenSource.CancelAfter(1000);
 var testTask = Test(_cancellationTokenSource.Token);
 await testTask;
 "Stop".Dump();
}
asked Apr 25, 2017 at 12:20
8
  • 4
    Before moving to F#, make sure the C# code is working. Right now it's broken - async void should only be used for event handlers because it can't be awaited. Furthermore, cold tasks are never needed. Don't use them in C# Commented Apr 25, 2017 at 12:27
  • Thanks. Changed from void to Task return from Test, and from new Task to Task.Factory.StartNew. But I still observe the same behavior in the output. Commented Apr 25, 2017 at 12:40
  • 2
    Why did you use StartNew? Why not just await Test(cts.Token);? Or store the return value ot Test, ie var testTask = Test(_cancellationTokenSource.Token)? It's already a Task. async doesn't mean you need to start a task. It means that you await for an asynchronous operation like IO or calling a web service to complete, without blocking the current thread Commented Apr 25, 2017 at 12:43
  • 1
    I didn't downvote but there is a problem with this question. You ask how to translate something to F# when that something doesn't even work. You should be looking for tutorials on async/await. Things won't be easier if you switch to F# Commented Apr 25, 2017 at 13:32
  • 1
    Tasks and async/await are equivalent to an async block Commented Apr 25, 2017 at 15:20

1 Answer 1

6

F# asynchronous workflows have built-in support for cancellation, so using those instead of working with tasks will probably make your life a lot easier. Your question does not really provide enough information to understand what you are trying to do, but below is an example of using async for something that is very close to your example:

let delayNe ms = async {
 use! _d = Async.OnCancel(fun () -> 
 printfn "cancelled!")
 do! Async.Sleep(ms) }
let test = async {
 printfn "Test start"
 do! delayNe 5000
 printfn "Test stop" }
let DoWork () = 
 let cts = new System.Threading.CancellationTokenSource()
 cts.CancelAfter(1000)
 Async.StartAsTask(test, cancellationToken = cts.Token)

The DoWork function starts the work as a task, which can be easily consumed from C#.

answered Apr 25, 2017 at 13:36
Sign up to request clarification or add additional context in comments.

4 Comments

In C# I want to do the equivalent of calling await Task.Delay(ms, token); so that I can abort the delay, but without having it throw the exception. So I want a wrapper for that, but implemented in F#. Thanks, I am trying to use this now.
Async.Sleep works well with the F# cancellation mechanism - it will not throw an exception and you can handle cancellation using Async.OnCancel. I suspect you are doing all this for some reason - so if you can share the reason, you might get a better advice.
Thanks, and I just added some explanation to the question.
I see - in that case, this should not be a problem in F#, because cancellation is not handled via ordinary exceptions :)

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.