Panoramica del supporto asincrono

C# 5 ha introdotto due parole chiave per semplificare il programma asincrono: async e await. Queste parole chiave consentono di scrivere codice semplice che usa Task Parallel Library per eseguire operazioni a esecuzione prolungata ,ad esempio l'accesso alla rete, in un altro thread e accedere facilmente ai risultati al completamento. Le versioni più recenti di Xamarin.iOS e Xamarin.Android supportano async e await. Questo documento fornisce spiegazioni e un esempio di uso della nuova sintassi con Xamarin.

Il supporto asincrono di Xamarin è basato sulla base di Mono 3.0 e aggiorna il profilo API dalla versione di Silverlight per dispositivi mobili per essere una versione di .NET 4.5 per dispositivi mobili.

Panoramica

Questo documento presenta le nuove parole chiave async e await e illustra alcuni semplici esempi che implementano metodi asincroni in Xamarin.iOS e Xamarin.Android.

Per una descrizione più completa delle nuove funzionalità asincrone di C# 5 (inclusi molti esempi e diversi scenari di utilizzo) vedere l'articolo Programmazione asincrona.

L'applicazione di esempio effettua una semplice richiesta Web asincrona (senza bloccare il thread principale) quindi aggiorna l'interfaccia utente con il numero di caratteri e html scaricato.

L'applicazione di esempio effettua una semplice richiesta Web asincrona senza bloccare il thread principale, quindi aggiorna l'interfaccia utente con il numero di caratteri e html scaricato

Il supporto asincrono di Xamarin si basa sulla base di Mono 3.0 e aggiorna il profilo API dalla versione di Silverlight per dispositivi mobili per essere una versione di .NET 4.5 per dispositivi mobili.

Requisiti

Le funzionalità C# 5 richiedono Mono 3.0 incluso in Xamarin.iOS 6.4 e Xamarin.Android 4.8. Verrà richiesto di aggiornare Mono, Xamarin.iOS, Xamarin.Android e Xamarin.Mac per sfruttarne i vantaggi.

Uso di async & await

async e await sono nuove funzionalità del linguaggio C# che funzionano insieme a Task Parallel Library per semplificare la scrittura di codice threadato per eseguire attività a esecuzione prolungata senza bloccare il thread principale dell'applicazione.

async

Dichiarazione

La async parola chiave viene inserita in una dichiarazione di metodo (o in un metodo lambda o anonimo) per indicare che contiene codice che può essere eseguito in modo asincrono, ovvero non bloccare il thread del chiamante.

Un metodo contrassegnato con async deve contenere almeno un'espressione o un'istruzione await. Se nel metodo non await sono presenti istruzioni, verrà eseguita in modo sincrono (come se non fosse presente alcun async modificatore). Verrà generato anche un avviso del compilatore , ma non un errore.

Tipi restituiti

Un metodo asincrono deve restituire un Taskoggetto o Task<TResult> void.

Specificare il Task tipo restituito se il metodo non restituisce alcun altro valore.

Specificare Task<TResult> se il metodo deve restituire un valore, dove TResult è il tipo restituito, ad esempio , int.

Il void tipo restituito viene usato principalmente per i gestori eventi che lo richiedono. Il codice che chiama metodi asincroni che restituiscono void non await può essere eseguito sul risultato.

Parametri

I metodi asincroni non possono dichiarare ref o out parametri.

await

L'operatore await può essere applicato a un oggetto Task all'interno di un metodo contrassegnato come asincrono. Fa sì che il metodo arresti l'esecuzione a quel punto e attenda il completamento dell'attività.

L'uso di await non blocca il thread del chiamante, ma il controllo viene restituito al chiamante. Ciò significa che il thread chiamante non è bloccato, quindi, ad esempio, il thread dell'interfaccia utente non verrà bloccato quando si attende un'attività.

Al termine dell'attività, il metodo riprende l'esecuzione nello stesso punto del codice. Ciò include la restituzione all'ambito try di un blocco try-catch-finally (se presente). await non può essere usato in un blocco catch o finally.

Altre informazioni su await.

Gestione delle eccezioni

Le eccezioni che si verificano all'interno di un metodo asincrono vengono archiviate nell'attività e generate quando l'attività è awaited. Queste eccezioni possono essere rilevate e gestite all'interno di un blocco try-catch.

Annullamento

I metodi asincroni che richiedono molto tempo per il completamento devono supportare l'annullamento. In genere, l'annullamento viene richiamato come segue:

  • Viene creato un CancellationTokenSource oggetto .
  • L'istanza CancellationTokenSource.Token viene passata a un metodo asincrono annullabile.
  • L'annullamento viene richiesto chiamando il CancellationTokenSource.Cancel metodo .

L'attività annulla quindi se stessa e riconosce l'annullamento.

Per altre informazioni sull'annullamento, vedere Ottimizzazione dell'app asincrona (C#).

Esempio

Scaricare l'esempio (per iOS e Android) per visualizzare un esempio funzionante di async e await nelle app per dispositivi mobili. Il codice di esempio viene illustrato in modo più dettagliato in questa sezione.

Scrittura di un metodo asincrono

Il metodo seguente illustra come codificare un async metodo con un'attività awaited:

public async Task<int> DownloadHomepage()
{
    var httpClient = new HttpClient(); // Xamarin supports HttpClient!

    Task<string> contentsTask = httpClient.GetStringAsync("https://visualstudio.microsoft.com/xamarin"); // async method!

    // await! control returns to the caller and the task continues to run on another thread
    string contents = await contentsTask;

    ResultEditText.Text += "DownloadHomepage method continues after async call. . . . .\n";

    // After contentTask completes, you can calculate the length of the string.
    int exampleInt = contents.Length;

    ResultEditText.Text += "Downloaded the html and found out the length.\n\n\n";

    ResultEditText.Text += contents; // just dump the entire HTML

    return exampleInt; // Task<TResult> returns an object of type TResult, in this case int
}

Tenere presente quanto segue:

  • La dichiarazione del metodo include la async parola chiave .
  • Il tipo restituito è Task<int> in modo che il codice chiamante possa accedere al int valore calcolato in questo metodo.
  • L'istruzione return è return exampleInt; un oggetto integer, ovvero il fatto che il metodo restituisce Task<int> fa parte dei miglioramenti del linguaggio.

Chiamata di un metodo asincrono 1

Questo pulsante click gestore eventi è reperibile nell'applicazione di esempio Android per chiamare il metodo descritto in precedenza:

GetButton.Click += async (sender, e) => {

    Task<int> sizeTask = DownloadHomepage();

    ResultTextView.Text = "loading...";
    ResultEditText.Text = "loading...\n";

    // await! control returns to the caller
    var intResult = await sizeTask;

    // when the Task<int> returns, the value is available and we can display on the UI
    ResultTextView.Text = "Length: " + intResult ;
    // "returns" void, since it's an event handler
};

Note:

  • Il delegato anonimo ha il prefisso della parola chiave asincrona.
  • Il metodo asincrono DownloadHomepage restituisce un oggetto Task<int> archiviato nella variabile sizeTask.
  • Il codice è in attesa nella variabile sizeTask. Si tratta del percorso in cui il metodo viene sospeso e il controllo viene restituito al codice chiamante fino al termine dell'attività asincrona nel proprio thread.
  • L'esecuzione non viene sospesa quando l'attività viene creata nella prima riga del metodo, nonostante l'attività creata in questa posizione. La parola chiave await indica la posizione in cui viene sospesa l'esecuzione.
  • Al termine dell'attività asincrona, intResult viene impostato e l'esecuzione continua sul thread originale, dalla riga await.

Chiamata di un metodo asincrono 2

Nell'applicazione di esempio iOS l'esempio viene scritto leggermente in modo diverso per illustrare un approccio alternativo. Anziché usare un delegato anonimo, questo esempio dichiara un async gestore eventi assegnato come un gestore eventi normale:

GetButton.TouchUpInside += HandleTouchUpInside;

Il metodo del gestore eventi viene quindi definito come illustrato di seguito:

async void HandleTouchUpInside (object sender, EventArgs e)
{
    ResultLabel.Text = "loading...";
    ResultTextView.Text = "loading...\n";

    // await! control returns to the caller
    var intResult = await DownloadHomepage();

    // when the Task<int> returns, the value is available and we can display on the UI
    ResultLabel.Text = "Length: " + intResult ;
}

Alcuni punti importanti:

  • Il metodo è contrassegnato come async ma restituisce void . Questa operazione viene in genere eseguita solo per i gestori eventi (in caso contrario si restituirà o Task Task<TResult> ).
  • La await parola chiave nel DownloadHomepage metodo assegna direttamente a una variabile (intResult) a differenza dell'esempio precedente in cui è stata usata una variabile intermedia Task<int> per fare riferimento all'attività. Si tratta della posizione in cui il controllo viene restituito al chiamante fino al completamento del metodo asincrono in un altro thread.
  • Quando il metodo asincrono viene completato e restituito, l'esecuzione riprende in corrispondenza del await che significa che il risultato intero viene restituito e quindi sottoposto a rendering in un widget dell'interfaccia utente.

Riepilogo

L'uso di async e await semplifica notevolmente il codice necessario per generare operazioni a esecuzione prolungata sui thread in background senza bloccare il thread principale. Semplificano anche l'accesso ai risultati quando l'attività è stata completata.

Questo documento ha fornito una panoramica delle nuove parole chiave del linguaggio ed esempi per Xamarin.iOS e Xamarin.Android.