Ho appena ricevuto VS2012 e sto provando a gestire async.
Diciamo che ho un metodo che recupera un valore da una fonte bloccante. Non voglio bloccare il chiamante del metodo. Potrei scrivere il metodo per prendere un callback che viene invocato quando arriva il valore, ma poiché sto usando C # 5, decido di rendere il metodo asincrono in modo che i chiamanti non debbano gestire i callback:
// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
Ecco un metodo di esempio che lo chiama. Se PromptForStringAsyncnon fosse asincrono, questo metodo richiederebbe l'annidamento di una richiamata all'interno di una richiamata. Con async, riesco a scrivere il mio metodo in questo modo molto naturale:
public static async Task GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
Console.WriteLine("Welcome {0}.", firstname);
string lastname = await PromptForStringAsync("Enter your last name: ");
Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}
Fin qui tutto bene. Il problema è quando chiamo GetNameAsync:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
L'intero punto di GetNameAsync è che è asincrono. Non voglio che si blocchi, perché voglio tornare a MainWorkOfApplicationIDontWantBlocked al più presto e lasciare che GetNameAsync faccia le sue cose in background. Tuttavia, chiamarlo in questo modo mi dà un avvertimento compilatore sulla GetNameAsynclinea:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
Sono perfettamente consapevole che "l'esecuzione del metodo corrente continua prima che la chiamata venga completata". Questo è il punto del codice asincrono, giusto?
Preferisco che il mio codice venga compilato senza avvisi, ma non c'è nulla da "correggere" qui perché il codice sta facendo esattamente quello che intendo. Posso eliminare l'avviso memorizzando il valore restituito diGetNameAsync :
public static void DoStuff()
{
var result = GetNameAsync(); // supress warning
MainWorkOfApplicationIDontWantBlocked();
}
Ma ora ho un codice superfluo. Visual Studio sembra capire che sono stato costretto a scrivere questo codice non necessario, perché sopprime il normale avviso "valore mai usato".
Posso anche liberarmi dell'avvertimento avvolgendo GetNameAsync in un metodo che non è asincrono:
public static Task GetNameWrapper()
{
return GetNameAsync();
}
Ma questo è pari più codice superfluo. Quindi devo scrivere il codice che non mi serve o tollero un avvertimento non necessario.
C'è qualcosa nel mio uso di asincrono che è sbagliato qui?
GetNameAsyncfornire il nome completo che è stato fornito dall'utente (ad esempio Task<Name>, piuttosto che restituire un Task? DoStuffPotrebbe quindi memorizzare tale compito, e sia awaitesso dopo l'altro metodo, o anche passare il compito di quell'altra metodo in modo che poteva awaito Waitda qualche parte all'interno di esso di implementazione.
asyncparola chiave.
PromptForStringAsyncfai più lavoro del necessario; restituisci solo il risultato diTask.Factory.StartNew. È già un'attività il cui valore è la stringa immessa nella console. Non è necessario attendere che ritorni il risultato; così facendo non si aggiunge alcun nuovo valore.