269 votes

Comment appeler une méthode asynchrone depuis un getter ou un setter ?

Quelle serait la manière 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'aider à m'expliquer.

async Task<IEnumerable> MyAsyncMethod()
{
    return await DoSomethingAsync();
}

public IEnumerable MyList
{
    get
    {
         //call MyAsyncMethod() here
    }
}

4 votes

Ma question serait de savoir pourquoi. Une propriété est censée imiter quelque chose comme un champ en ce sens qu'elle doit généralement effectuer peu de travail (ou du moins très rapidement). Si vous avez une propriété de longue durée, il vaut mieux l'écrire comme une méthode pour que l'appelant sache qu'il s'agit d'un travail plus complexe.

0 votes

@James : C'est exactement ça - et je soupçonne que c'est la raison pour laquelle cela n'a pas été explicitement pris en charge dans le CTP. Ceci étant dit, vous pouvez toujours rendre la propriété de type Task<T> qui retournera immédiatement, aura une sémantique de propriété normale, et permettra toujours de traiter les choses de manière asynchrone si nécessaire.

19 votes

James Mon besoin découle de l'utilisation de Mvvm et de Silverlight. Je veux pouvoir me lier à une propriété, où le chargement des données se fait paresseusement. La classe d'extension ComboBox que j'utilise exige que la liaison se fasse à l'étape InitializeComponent(), mais le chargement réel des données se fait beaucoup plus tard. En essayant d'accomplir avec aussi peu de code que possible, getter et async semble être la combinaison parfaite.

-1voto

user2033402 Points 117

Lorsque j'ai rencontré ce problème, essayer d'exécuter une méthode asynchrone de manière synchrone à partir d'un setter ou d'un constructeur me mettait dans une impasse sur le thread de l'interface utilisateur, et l'utilisation d'un gestionnaire d'événements nécessitait trop de changements dans la conception générale.
La solution a été, comme souvent, d'écrire explicitement ce que je voulais qu'il se passe implicitement, c'est-à-dire qu'un autre thread gère l'opération et que le thread principal attende qu'elle se termine :

string someValue=null;
var t = new Thread(() =>someValue = SomeAsyncMethod().Result);
t.Start();
t.Join();

On pourrait dire que j'abuse du cadre, mais ça marche.

-1voto

Mahdi Rastegari Points 83

J'examine toutes les réponses mais toutes ont un problème de performance.

par exemple dans :

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");
        }
    }
}

Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle() ; }) ;

utiliser le dispatcher qui n'est pas une bonne réponse.

mais il y a une solution simple, il suffit de le faire :

string _Title;
    public string Title
    {
        get
        {
            if (_Title == null)
            {   
                Task.Run(()=> 
                {
                    _Title = getTitle();
                    RaisePropertyChanged("Title");
                });        
                return;
            }
            return _Title;
        }
        set
        {
            if (value != _Title)
            {
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }
    }

-2voto

heyyan khan Points 175

Vous pouvez l'utiliser pour la suite

    async Task<IEnumerable> MyAsyncMethod()
    {
        return await DoSomethingAsync();
    }

    public IEnumerable MyList
    {
        get
        {
            MyAsyncMethod()
              .ContinueWith((tsk) =>
              {
                  // what every work 
              });
        }
    }

-5voto

Vous pouvez changer la propriété en Task<IEnumerable>

et faire quelque chose comme :

get
{
    Task<IEnumerable>.Run(async()=>{
       return await getMyList();
    });
}

et l'utiliser comme await MaListe ;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X