Qual seria a maneira mais elegante de chamar um método assíncrono de um getter ou setter em C #?
Aqui estão alguns pseudo-códigos para ajudar a me explicar.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, que retornará imediatamente, ter semântica de propriedade normal e ainda permitir que as coisas sejam tratadas de forma assíncrona, conforme necessário.Respostas:
Não há razão técnica para que
async
propriedades não sejam permitidas em C #. Foi uma decisão de projeto proposital, porque "propriedades assíncronas" é um oxímoro.Propriedades devem retornar valores atuais; eles não devem iniciar operações em segundo plano.
Normalmente, quando alguém deseja uma "propriedade assíncrona", o que realmente deseja é um destes:
async
métodoasync
método de fábrica para o objeto que contém ou use umasync InitAsync()
método. O valor vinculado aos dados serádefault(T)
até que o valor seja calculado / recuperado.AsyncLazy
no meu blog ou na biblioteca AsyncEx . Isso lhe dará umaawait
propriedade capaz.Update: Eu cobrir propriedades assíncronas em um dos meus últimos "assíncronos OOP" posts.
fonte
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
e decidir se deseja que o valor antigo seja retornado oudefault(T)
enquanto a atualização assíncrona estiver em andamento.NotifyTaskCompletion
do meu projeto AsyncEx . Ou você pode construir o seu próprio; não é tão difícil.{Binding PropName.Result}
não é trivial para eu descobrir.Você não pode chamá-lo de forma assíncrona, pois não há suporte a propriedades assíncronas, apenas métodos assíncronos. Como tal, existem duas opções, ambas aproveitando o fato de que os métodos assíncronos no CTP são realmente apenas um método que retorna
Task<T>
ouTask
:Ou:
fonte
private async void SetupList() { MyList = await MyAsyncMethod(); }
Isso faria com que MyList a ser definido (e, então, automaticamente ligam, se ele implementa INPC), logo que os conclui operação assíncrona ...getTitle()
simulatenously ...Eu realmente precisava da chamada para se originar do método get, devido à minha arquitetura desacoplada. Então, eu vim com a seguinte implementação.
Uso: o título está em um ViewModel ou em um objeto que você pode declarar estaticamente como um recurso de página. Associe-se a ele e o valor será preenchido sem bloquear a interface do usuário, quando getTitle () retornar.
fonte
Acho que podemos aguardar o valor retornando primeiro nulo e, em seguida, obtendo o valor real, portanto, no caso do Pure MVVM (projeto PCL por exemplo), acho que a seguinte é a solução mais elegante:
fonte
CS4014: Async method invocation without an await expression
async void
apenas para manipuladores de nível superior e afins". Eu acho que isso pode se qualificar como "e seu gosto".Você pode usar
Task
assim:fonte
Eu pensei que. GetAwaiter (). GetResult () era exatamente a solução para este problema, não? por exemplo:
fonte
.Result
- não é assíncrono e pode resultar em conflitos.Como sua "propriedade assíncrona" está em um modelo de exibição, você pode usar o AsyncMVVM :
Ele cuidará do contexto de sincronização e da notificação de alteração de propriedade para você.
fonte
Necromante.
No .NET Core / NetStandard2, você pode usar em
Nito.AsyncEx.AsyncContext.Run
vez deSystem.Windows.Threading.Dispatcher.InvokeAsync
:Se você simplesmente escolheu
System.Threading.Tasks.Task.Run
ouSystem.Threading.Tasks.Task<int>.Run
, então não funcionaria.fonte
Acho que meu exemplo abaixo pode seguir a abordagem de Stephen-Cleary, mas eu queria dar um exemplo codificado. Isso é para uso em um contexto de ligação de dados, por exemplo, Xamarin.
O construtor da classe - ou mesmo o criador de outra propriedade da qual depende - pode chamar um vazio assíncrono que preencherá a propriedade após a conclusão da tarefa sem a necessidade de aguardar ou bloquear. Quando finalmente obtiver um valor, atualizará sua interface do usuário por meio do mecanismo NotifyPropertyChanged.
Não tenho certeza sobre nenhum efeito colateral de chamar um aysnc de um construtor. Talvez um comentarista elabore um tratamento de erro, etc.
fonte
Quando me deparei com esse problema, tentar executar uma sincronicidade de método assíncrono de um setter ou de um construtor me levou a um impasse no encadeamento da interface do usuário, e o uso de um manipulador de eventos exigiu muitas alterações no design geral.
A solução era, como sempre é, escrever explicitamente o que eu queria que acontecesse implicitamente, que era ter outro thread para lidar com a operação e fazer com que o thread principal esperasse o término:
Você poderia argumentar que eu abusei da estrutura, mas funciona.
fonte
Analiso todas as respostas, mas todas têm um problema de desempenho.
por exemplo em:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Title = aguardar getTitle ();});
use despachante que não é uma boa resposta.
mas existe uma solução simples, basta fazê-lo:
fonte
Você pode alterar a propriedade para
Task<IEnumerable>
e faça algo como:
e use-o como aguarde MyList;
fonte