Quel serait le moyen le plus élégant 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
}
}
J'avais vraiment besoin que l'appel provienne de la méthode get, en raison de mon architecture découplée. Je suis donc venu avec la mise en œuvre suivante.
sage: Titre se trouve dans un ViewModel ou un objet que vous pouvez déclarer de manière statique en tant que ressource de page. Si vous le liez, la valeur sera remplie sans bloquer l'interface utilisateur lorsque getTitle () sera renvoyé.
string _Title;
public string Title
{
get
{
if (_Title == null)
{
Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); });
}
return _Title;
}
set
{
if (value != _Title)
{
_Title = value;
RaisePropertyChanged("Title");
}
}
}
Il n'y a pas de raison technique pour laquelle les propriétés async
ne sont pas autorisées en C #. C'était une décision de conception délibérée, parce que "propriétés asynchrones" est un oxymoron.
Les propriétés doivent renvoyer les valeurs actuelles. ils ne devraient pas lancer des opérations en arrière-plan.
Habituellement, lorsque quelqu'un veut une "propriété asynchrone", il souhaite réellement l'une de ces options:
async
.async
pour l'objet contenant ou une méthode async InitAsync()
. La valeur liée aux données sera default(T)
jusqu'à ce que la valeur soit calculée/extraite.AsyncLazy
de mon blog ou bibliothèque AsyncEx . Cela vous donnera une propriété await
able.Mise à jour: Je couvre propriétés asynchrones dans l'un de mes derniers articles de blog "asynchrones".
Vous ne pouvez pas l'appeler de manière asynchrone, car il n'y a pas de support de propriété asynchrone, seulement des méthodes async. En tant que tel, il existe deux options, toutes deux tirant parti du fait que les méthodes asynchrones du CTP ne sont en réalité qu'une méthode qui renvoie Task<T>
ou Task
:
// Make the property return a Task<T>
public Task<IEnumerable> MyList
{
get
{
// Just call the method
return MyAsyncMethod();
}
}
Ou:
// Make the property blocking
public IEnumerable MyList
{
get
{
// Block via .Result
return MyAsyncMethod().Result;
}
}
Je pense que nous pouvons attendre la valeur en retournant d’abord la valeur null, puis la valeur réelle. Par conséquent, dans le cas de Pure MVVM (projet PCL, par exemple), je pense que la solution suivante est la plus élégante:
private IEnumerable myList;
public IEnumerable MyList
{
get
{
if(myList == null)
InitializeMyList();
return myList;
}
set
{
myList = value;
NotifyPropertyChanged();
}
}
private async void InitializeMyList()
{
MyList = await AzureService.GetMyList();
}
Je pensais que. GetAwaiter (). GetResult () était exactement la solution à ce problème, non? par exemple:
string _Title;
public string Title
{
get
{
if (_Title == null)
{
_Title = getTitle().GetAwaiter().GetResult();
}
return _Title;
}
set
{
if (value != _Title)
{
_Title = value;
RaisePropertyChanged("Title");
}
}
}
Puisque votre "propriété async" est dans un modèle de vue, vous pouvez utiliser AsyncMVVM :
class MyViewModel : AsyncBindableBase
{
public string Title
{
get
{
return Property.Get(GetTitleAsync);
}
}
private async Task<string> GetTitleAsync()
{
//...
}
}
Il se chargera du contexte de synchronisation et de la notification de changement de propriété pour vous.
Vous pouvez utiliser Task
comme ceci:
public int SelectedTab
{
get => selected_tab;
set
{
selected_tab = value;
new Task(async () =>
{
await newTab.ScaleTo(0.8);
}).Start();
}
}