web-dev-qa-db-fra.com

Impossible de convertir implicitement le type 'chaîne' en 'System.Threading.Tasks.Task <chaîne>'

Je suis nouveau dans la programmation asynchrone, alors après avoir lu quelques exemples de codes asynchrones, j'ai pensé écrire un code async simple

J'ai créé une application Winform simple et à l'intérieur du formulaire, j'ai écrit le code suivant. Mais ça ne marche pas

private Task<string> methodAsync() {
    Thread.Sleep(10000);
    return "Hello"; //Error: Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
}

private async void button1_Click(object sender, EventArgs e)
{
    string s = await methodAsync();
    MessageBox.Show(s);
}

Quelqu'un pourrait-il s'il vous plaît mettre un peu de lumière ici ..

57
dotNETbeginner

Le type de retour indiqué de la méthode est Task<string>. Vous essayez de retourner un string. Ils ne sont pas les mêmes, il n'y a pas non plus de conversion implicite de chaîne en Task<string>, D'où l'erreur.

Vous confondez probablement ceci avec une méthode async dans laquelle la valeur de retour est automatiquement encapsulée dans un objet Task par le compilateur. Actuellement, cette méthode n'est pas une méthode asynchrone. Vous vouliez presque certainement faire ceci:

private async Task<string> methodAsync() 
{
    await Task.Delay(10000);
    return "Hello";
}

Il y a deux changements clés. Premièrement, la méthode est marquée comme async, ce qui signifie que le type de retour est encapsulé dans un Task, ce qui rend la méthode compilée. Ensuite, nous ne voulons pas faire une attente bloquante. En règle générale, lorsque vous utilisez le modèle await, évitez toujours de bloquer les temps d'attente lorsque vous le pouvez. Task.Delay Est une tâche qui sera terminée après le nombre spécifié de millisecondes. En awaiting cette tâche, nous effectuons effectivement une attente non bloquante pendant ce temps (en réalité, le reste de la méthode est une continuation de cette tâche).

Si vous préférez une méthode 4.0, sans utiliser await, vous pouvez le faire:

private Task<string> methodAsync() 
{
    return Task.Delay(10000)
        .ContinueWith(t => "Hello");
}

La première version compilera quelque chose qui ressemble plus ou moins à cela, mais il y aura du code standard supplémentaire pour supporter la gestion des erreurs et d'autres fonctionnalités de await que nous n'utilisons pas ici.

Si votre Thread.Sleep(10000) est vraiment destinée à être un espace réservé pour une méthode longue, plutôt qu'un moyen d'attendre un moment, vous devrez alors vous assurer que le travail est effectué dans un autre thread. , au lieu du contexte actuel. Le moyen le plus simple de le faire consiste à utiliser Task.Run:

private Task<string> methodAsync() 
{
    return Task.Run(()=>
        {
            SomeLongRunningMethod();
            return "Hello";
        });
}

Ou plus probablement:

private Task<string> methodAsync() 
{
    return Task.Run(()=>
        {
            return SomeLongRunningMethodThatReturnsAString();
        });
}
102
Servy

Utiliser la méthode FromResult

public async Task<string> GetString()
{
   System.Threading.Thread.Sleep(5000);
   return await Task.FromResult("Hello");
}
34
Jaswant Agarwal

Au-delà de l'utilisation problématique de async comme l'a souligné @Servy, vous devez également obtenir explicitement T de Task<T> en appelant Task.Result. Notez que la propriété Result bloque le code asynchrone et doit être utilisée avec précaution.

Essayer:

private async void button1_Click(object sender, EventArgs e)
{
    var s = await methodAsync();
    MessageBox.Show(s.Result);
}
19
user2388853