Async.FromContinuations<'T>, méthode (F#)
Crée un calcul asynchrone qui capture les continuations de réussite, d'exception et d'annulation actuelles.Le rappel doit ensuite appeler exactement l'une des continuations données.
Espace de noms/Chemin du module : Microsoft.FSharp.Control
Assembly : FSharp.Core (in FSharp.Core.dll)
// Signature:
static member FromContinuations : (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
// Usage:
Async.FromContinuations (callback)
Paramètres
callback
Type : ('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unitFonction qui accepte les continuations de réussite, d'exception et d'annulation actuelles.
Valeur de retour
Calcul asynchrone qui fournit au rappel les continuations actuelles.
Notes
L'argument de cette méthode est une expression lambda qui prend trois fonctions de suite, qui sont généralement appelées cont (la suite de réussite), ccont (la suite d'annulation) et econt (la suite d'erreur), comme l'illustre le code suivant :
Async.FromContinuations (fun (cont, ccont, econt) -> ...)
Attention |
---|
Si vous utilisez cette méthode, vous devez appeler exactement l'une des fonctions de suite ou bien lever une exception dans ce cas, F# appelle econt avec l'exception en votre nom.Si vous appelez plusieurs suite, appelez une suite plusieurs fois, ou appelez une suite et lève une exception, toute utilisation ultérieure de l'objet résultant async peut avoir un comportement. |
Exemple
L'exemple suivant illustre comment utiliser Async.FromContinuations pour encapsuler un calcul asynchrone basé sur un événement comme une fonction F# asynchrone.
open System
open System.ComponentModel
open System.Windows.Forms
type BackgroundWorker with
member this.AsyncRunWorker (computation, argument : 'T, progressChangedHandler) : Async<'U> =
let workerAsync =
Async.FromContinuations (fun (cont, econt, ccont) ->
let handler = new RunWorkerCompletedEventHandler (fun sender args ->
if args.Cancelled then
ccont (new OperationCanceledException())
elif args.Error <> null then
econt args.Error
else
cont (args.Result :?> 'U))
this.WorkerSupportsCancellation <- true;
this.WorkerReportsProgress <- true
this.DoWork.AddHandler(new DoWorkEventHandler(fun sender args ->
args.Result <- computation(argument, this, args)))
this.ProgressChanged.AddHandler(progressChangedHandler)
this.RunWorkerCompleted.AddHandler(handler)
this.RunWorkerAsync(argument)
)
async {
use! holder = Async.OnCancel(fun _ -> this.CancelAsync())
return! workerAsync
}
let factorial number =
let rec fact number =
match number with
| value when value < 0I ->
raise (InvalidOperationException(sprintf "Cannot compute the factorial of a negative number: %s." (value.ToString())))
| value when value > 2000I ->
raise (InvalidOperationException(sprintf "Input too large: %s" (value.ToString())))
| value when value = 0I -> 1I
| value when value = 1I -> 1I
| number -> number * fact (number - 1I)
fact number
// Recursive isprime function.
let isprime number =
let rec check count =
count > number/2 || (number % count <> 0 && check (count + 1))
check 2
let isprimeBigInt number =
let rec check count =
count > number/2I || (number % count <> 0I && check (count + 1I))
check 2I
let computeNthPrime (number, worker: BackgroundWorker, eventArgs: DoWorkEventArgs) =
if (number < 1) then
invalidOp <| sprintf "Invalid input for nth prime: %s." (number.ToString())
let mutable count = 0
let mutable num = 1I
let isDone = false
while (count < number && not eventArgs.Cancel ) do
if (worker.CancellationPending) then
eventArgs.Cancel <- true
else
let percentComplete = int ((float count) / (float number) * 100.0)
worker.ReportProgress(percentComplete, num.ToString())
num <- num + 1I
if (num < bigint System.Int32.MaxValue) then
while (not (isprime (int num))) do
num <- num + 1I
else
while (not (isprimeBigInt num)) do
num <- num + 1I
count <- count + 1
num
let async1 (progressBar:ProgressBar) (label:Label) value =
let worker = new BackgroundWorker()
label.Text <- "Computing..."
let computation value = worker.AsyncRunWorker(computeNthPrime, value,
(fun sender eventArgs ->
label.Text <- "Scanning ... " + eventArgs.UserState.ToString()
progressBar.Value <- eventArgs.ProgressPercentage ))
Async.StartWithContinuations(
computation value,
(fun result -> label.Text <- sprintf "Result: %s" (result.ToString())),
(fun exn -> label.Text <- "Operation failed with error:" + exn.Message),
(fun _ -> label.Text <- "Operation canceled."))
let form = new Form(Text = "Test Form", Width = 400, Height = 400)
let panel1 = new Panel(Dock = DockStyle.Fill)
panel1.DockPadding.All <- 10
let spacing = 5
let button1 = new Button(Text = "Start")
let button2 = new Button(Text = "Start Invalid", Top = button1.Height + spacing)
let button3 = new Button(Text = "Cancel", Top = 2 * (button1.Height + spacing))
let updown1 = new System.Windows.Forms.NumericUpDown(Top = 3 * (button1.Height + spacing),
Value = 20m,
Minimum = 0m,
Maximum = 1000000m)
let label1 = new Label (Text = "", Top = 4 * (button1.Height + spacing),
Width = 300, Height = 2 * button1.Height)
let progressBar = new ProgressBar(Top = 6 * (button1.Height + spacing),
Width = 300)
panel1.Controls.AddRange [| button1; button2; button3; updown1; label1; progressBar; |]
form.Controls.Add(panel1)
button1.Click.Add(fun args -> async1 progressBar label1 (int updown1.Value))
button2.Click.Add(fun args -> async1 progressBar label1 (int (-updown1.Value)))
button3.Click.Add(fun args -> Async.CancelDefaultToken())
Application.Run(form)
Plateformes
Windows 8, Windows 7, Windows Server 2012, Windows Server 2008 R2
Informations de version
Versions de bibliothèque principale F#
Prise en charge dans : 2,0, 4,0, portables