Ouvi em algum lugar que o C # 5 async-waitit será tão incrível que você não precisará se preocupar em fazer isso:
if (InvokeRequired)
{
BeginInvoke(...);
return;
}
// do your stuff here
Parece que o retorno de chamada de uma operação de espera ocorrerá no encadeamento original do chamador. Eric Lippert e Anders Hejlsberg afirmaram várias vezes que esse recurso se originou da necessidade de tornar as interfaces de usuário (principalmente as de dispositivo de toque) mais responsivas.
Eu acho que um uso comum desse recurso seria algo como isto:
public class Form1 : Form
{
// ...
async void GetFurtherInfo()
{
var temperature = await GetCurrentTemperatureAsync();
label1.Text = temperature;
}
}
Se apenas um retorno de chamada for usado, a configuração do texto do rótulo gerará uma exceção, pois não está sendo executado no encadeamento da interface do usuário.
Até agora, não consegui encontrar nenhum recurso confirmando que esse seja o caso. Alguém sabe sobre isso? Existem documentos explicando tecnicamente como isso funcionará?
Por favor, forneça um link de uma fonte confiável, não basta responder "sim".
fonte
await
funcionalidade. É apenas muito açúcar sintático para a passagem contínua . Possivelmente, existem outras melhorias não relacionadas ao WinForms que devem ajudar? Isso seria abrangido pelo próprio framework .NET, e não pelo C # especificamente.Respostas:
Acho que você está confundindo algumas coisas aqui. O que você está pedindo é já possível usando
System.Threading.Tasks
, oasync
eawait
em C # 5 está indo só para proporcionar um pouco de açúcar sintático mais agradável para o mesmo recurso.Vamos usar um exemplo do Winforms - solte um botão e uma caixa de texto no formulário e use este código:
Execute-o e você verá que (a) ele não bloqueia o encadeamento da interface do usuário e (b) você não recebe o erro "operação de encadeamento inválida" usual - a menos que você remova o
TaskScheduler
argumento do últimoContinueWith
, em Nesse caso, você irá.Este é o padrão do pântano estilo de passagem de continuação . A mágica acontece na
TaskScheduler
classe e, especificamente, na instância recuperada porFromCurrentSynchronizationContext
. Passe isso para qualquer continuação e você diz que a continuação deve ser executada em qualquer thread chamadoFromCurrentSynchronizationContext
método - nesse caso, o thread da interface do usuário.Os garçons são um pouco mais sofisticados, no sentido de saberem em qual encadeamento iniciaram e em qual encadeamento a continuação precisa ocorrer. Portanto, o código acima pode ser escrito um pouco mais naturalmente:
Esses dois devem parecer muito semelhantes e, de fato, são muito semelhantes. o
DelayedAddAsync
método agora retorna um emTask<int>
vez de umint
e, portanto,await
está apenas colocando continuações em cada uma delas. A principal diferença é que ela está transmitindo o contexto de sincronização em cada linha, para que você não precise fazer isso explicitamente, como fizemos no último exemplo.Em teoria, as diferenças são muito mais significativas. No segundo exemplo, todas as linhas do
button1_Click
método são realmente executadas no thread da interface do usuário, mas a própria tarefa (DelayedAddAsync
) é executada em segundo plano. No primeiro exemplo, tudo é executado em segundo plano , exceto a atribuição àtextBox1.Text
qual anexamos explicitamente o contexto de sincronização do thread da interface do usuário.É disso que realmente interessa
await
- o fato de um garçom ser capaz de entrar e sair do mesmo método sem nenhuma chamada de bloqueio. Você ligaawait
, o encadeamento atual volta ao processamento de mensagens e, quando terminar, o garçom retoma exatamente onde parou, no mesmo encadeamento em que parou. Mas, em termos de seuInvoke
/BeginInvoke
contraste na pergunta, eu ' Lamento dizer que você deveria ter parado de fazer isso há muito tempo.fonte
ArrayList
classe no novo código. Eu ainda quase não tenho nenhuma experiência com o RX. As pessoas aprendem o que precisam saber e compartilham o que já sabem, mesmo que o que já sabem esteja desatualizado. Essa resposta pode estar desatualizada em alguns anos.Sim, para o encadeamento da interface do usuário, o retorno de chamada de uma operação de espera ocorrerá no encadeamento original do chamador.
Eric Lippert escreveu uma série de 8 partes sobre o assunto há um ano: Fabulous Adventures In Coding
EDIT: e aqui está o // build / apresentação de Anders : channel9
BTW, você notou que, se você virar "// build /" de cabeça para baixo, terá "/ plinq //" ;-)
fonte
Jon Skeet fez uma excelente apresentação sobre os métodos Async no C # 5, que você pode achar extremamente útil:
http://skillsmatter.com/podcast/home/async-methods
fonte