Una cosa che ho sempre trovato scomoda utilizzando il pattern asincrono Begin/End e il fatto di dover gestire il metodo di callback e pensare a come continuare l’esecuzione del codice una volta finita l’operazione asincrona. Esempio:
…
SqlCommand comm = new SqlCommand(…)
conn.Open();
comm.BeginExecuteNonQuery(IAsync =>
{
int affectedRows = comm.EndExecuteNonQuery(IAsync);
conn.Close();
UICode(affectedRows);
}, ...);
…
Questa operazione diventa ancora più scomoda se come nell’esempio il modello di threading in cui callback deve finire ha constraint particolari(non possiamo modificare il codice di UI da un thread diverso dal creatore di quel controllo). Con l’arrivo delle TPL questo non è più un problema e il tutto diventa molto più elegante e chiaro. Ecco come possiamo fare attraverso l’utilizzo della API Task.Factory.FromAsync:
Task.Factory.FromAsync<int>(command.BeginExecuteNonQuery(),
(IAsync) => { return command.EndExecuteNonQuery(IAsync); })
.ContinueWith(t =>
{
int affectedRows = t.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
Carino no?Con la continuazione il codice diventa molto più facile e se non è ancora chiaro possiamo
mettere l’API in un extension method e far diventare il codice più semplice:
…
SqlCommand comm = new SqlCommand(…)
conn.Open();
comm.ExecuteAsyncWithResult().ContinueWith(task =>
{
int id = task.Result;
conn.Close();
},TaskScheduler.FromCurrentSynchronizationContext());
…
l’extension method:
public static class SqlCommandAsyncExtensionMethods
{
public static Task<int> ExecuteAsyncWithResult(this SqlCommand command)
{
return Task.Factory.FromAsync<int>(command.BeginExecuteNonQuery(),
(IAsync) => { return command.EndExecuteNonQuery(IAsync); });
}
}
Il SqlCommand è un esempio, FromAsync funziona con qualsiasi classe implementi il pattern
IAsync BeginXXX/EndXXX(IAsync)