2017-04-25 60 views
2

我想将C#方法DelayNe下面的语句翻译成F#函数,以便可以以完全相同的方式在C#中使用它。原因是我想把它放在一个F#库中。我努力尝试谷歌我的答案,显然没有运气,我挣扎了很多。将C#异步方法转换为F#函数

更新:对不起,不清楚。我的任务调用Task.Delay的方式可以在下面的DelayNe方法中看到。问题是当_cancellationTokenSource.Cancel()被调用时,那么Task.Delay会抛出一个异常,而我不想要这个异常。换句话说,我相信我需要一个围绕Task.Delay的包装器,它将捕获异常并将其消除,但否则完全按照原样公开Task.Delay的行为。我想在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(); 
} 
+4

在转到F#之前,请确保C#代码正在工作。现在它已经坏了 - 'async void'只能用于*事件处理程序*,因为它不能被等待。此外,冷的任务是不需要的。不要在C#中使用它们# –

+0

谢谢。从void更改为任务从Test返回,并从新任务更改为Task.Factory.StartNew。但我仍然在输出中观察到相同的行为。 –

+2

你为什么使用StartNew?为什么不只是'等待测试(cts.Token);'?或者存储返回值ot'Test',即'var testTask = Test(_cancellationTokenSource.Token)'?这已经是一个任务。 'async'并不意味着你需要开始一项任务。这意味着你*等待IO的异步操作或调用Web服务来完成,而不会阻塞当前线程 –

回答

6

F#异步工作流已经内置了对取消的支持,所以使用这些,而不是使用任务将可能使你的生活变得更加简单。你的问题并没有真正提供足够的信息来了解你正在尝试做的,但下面是一个使用async的东西的一个例子,这是非常接近你的例子:

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) 

DoWork功能开始工作作为任务,可以很容易地从C#中使用。

+0

在C#中,我想做相当于调用'await Task.Delay(ms,token);'这样我可以中止延迟,但不会抛出例外。所以我想要一个包装器,但在F#中实现。谢谢,我现在试着使用它。 –

+0

'Async.Sleep'与F#取消机制一起工作良好 - 它不会抛出异常,您可以使用'Async.OnCancel'处理取消。我怀疑你出于某种原因正在做这些 - 所以如果你能分享原因,你可能会得到更好的建议。 –

+0

谢谢,我只是给这个问题添加了一些解释。 –