Quelle serait la façon la plus élégante d'appeler une méthode asynchrone à partir d'un getter ou d'un setter en C #?
Voici un pseudo-code pour m'expliquer.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, qui reviendra immédiatement, aura une sémantique de propriété normale et permettra toujours aux choses d'être traitées de manière asynchrone selon les besoins.Réponses:
Il n'y a aucune raison technique
async
propriétés ne sont pas autorisées en C #. C'était une décision de conception délibérée, car les «propriétés asynchrones» sont un oxymore.Les propriétés doivent renvoyer les valeurs actuelles; ils ne devraient pas lancer d'opérations en arrière-plan.
Habituellement, quand quelqu'un veut une «propriété asynchrone», ce qu'il veut vraiment, c'est l'un d'entre eux:
async
méthode.async
méthode d'usine pour l'objet conteneur ou utilisez uneasync InitAsync()
méthode. La valeur liée aux données seradefault(T)
jusqu'à ce que la valeur soit calculée / récupérée.AsyncLazy
partir de mon blog ou de la bibliothèque AsyncEx . Cela vous donnera uneawait
propriété en mesure.Mise à jour: je couvre les propriétés asynchrones dans l'un de mes récents articles de blog "async OOP".
la source
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
, puis de décider si vous souhaitez que l'ancienne valeur soit renvoyée oudefault(T)
pendant que la mise à jour asynchrone est en cours.NotifyTaskCompletion
de mon projet AsyncEx . Ou vous pouvez construire le vôtre; ce n'est pas si dur.{Binding PropName.Result}
n'est pas triviale pour moi de le découvrir.Vous ne pouvez pas l'appeler de manière asynchrone, car il n'y a pas de prise en charge de propriété asynchrone, uniquement des méthodes asynchrones. En tant que tel, il existe deux options, les deux profitant du fait que les méthodes asynchrones dans le CTP ne sont en réalité qu'une méthode qui renvoie
Task<T>
ouTask
:Ou:
la source
private async void SetupList() { MyList = await MyAsyncMethod(); }
ci qui entraînerait la définition de MyList (puis la liaison automatique, si elle implémente INPC) dès que l'opération asynchrone est terminée ...getTitle()
simultanés ...J'avais vraiment besoin que l'appel provienne de la méthode get, en raison de mon architecture découplée. J'ai donc proposé l'implémentation suivante.
Utilisation: le titre est dans un ViewModel ou un objet que vous pouvez déclarer statiquement comme ressource de page. Liez-le et la valeur sera remplie sans bloquer l'interface utilisateur, lorsque getTitle () reviendra.
la source
Je pense que nous pouvons attendre que la valeur retourne d'abord null puis obtenir la valeur réelle, donc dans le cas de Pure MVVM (projet PCL par exemple), je pense que la solution la plus élégante est la suivante:
la source
CS4014: Async method invocation without an await expression
async void
uniquement pour les gestionnaires de haut niveau et similaires". Je pense que cela peut être qualifié de "et leurs semblables".Vous pouvez utiliser
Task
comme ceci:la source
Je pensais que .GetAwaiter (). GetResult () était exactement la solution à ce problème, non? par exemple:
la source
.Result
- ce n'est pas asynchrone et cela peut entraîner des blocages.Puisque votre "propriété async" est dans un modèle de vue, vous pouvez utiliser AsyncMVVM :
Il s'occupera du contexte de synchronisation et de la notification de changement de propriété pour vous.
la source
Nécromancement.
Dans .NET Core / NetStandard2, vous pouvez utiliser à la
Nito.AsyncEx.AsyncContext.Run
place deSystem.Windows.Threading.Dispatcher.InvokeAsync
:Si vous avez simplement choisi
System.Threading.Tasks.Task.Run
ouSystem.Threading.Tasks.Task<int>.Run
, cela ne fonctionnerait pas.la source
Je pense que mon exemple ci-dessous peut suivre l'approche de @ Stephen-Cleary mais je voulais donner un exemple codé. Ceci est destiné à être utilisé dans un contexte de liaison de données, par exemple Xamarin.
Le constructeur de la classe - ou bien le poseur d'une autre propriété dont il dépend - peut appeler un vide asynchrone qui remplira la propriété à la fin de la tâche sans avoir besoin d'attendre ou de bloquer. Lorsqu'il obtient enfin une valeur, il met à jour votre interface utilisateur via le mécanisme NotifyPropertyChanged.
Je ne suis pas certain des effets secondaires de l'appel d'un vide aysnc à partir d'un constructeur. Peut-être qu'un intervenant développera la gestion des erreurs, etc.
la source
Lorsque j'ai rencontré ce problème, essayer d'exécuter une synchronicité de méthode asynchrone à partir d'un setter ou d'un constructeur m'a mis dans une impasse sur le thread d'interface utilisateur, et l'utilisation d'un gestionnaire d'événements a nécessité trop de changements dans la conception générale.
La solution était, comme souvent, d'écrire explicitement ce que je voulais implicitement, c'est-à-dire d'avoir un autre thread pour gérer l'opération et pour que le thread principal attende qu'il se termine:
Vous pourriez dire que j'abuse du cadre, mais cela fonctionne.
la source
J'examine toutes les réponses, mais toutes ont un problème de performances.
par exemple dans:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Title = attendre getTitle ();});
utilisez dispatcher qui n'est pas une bonne réponse.
mais il existe une solution simple, faites-le:
la source
Vous pouvez changer la propriété en
Task<IEnumerable>
et faites quelque chose comme:
et l'utiliser comme attendre MyList;
la source