c#“任务方法”也可以是“异步”方法吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11714024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 18:56:25  来源:igfitidea点击:

c# Can a "task method" also be an "async" method?

c#asynchronousasync-awaitctp

提问by Michael Ray Lovett

I'm trying to get the hand of the new async CTP stuff and I'm probably confusing myself here.. I can have this "task method", with no problem:

我正在尝试掌握新的异步 CTP 东西,我可能在这里混淆了自己..我可以有这个“任务方法”,没有问题:

    public static Task<String> LongTaskAAsync() {
        return Task.Run(() => {
            return("AAA");
            });
        }

But what if I need the task to execute another task, can I mark it as "async" and use "await"? I tried this:

但是如果我需要任务来执行另一个任务,我可以将它标记为“async”并使用“await”吗?我试过这个:

public async static Task<String> LongTaskAAsync() {
        await Task.Delay(2000);
        return Task.Run(() => {
            return("AAA");
            });
        }

But then mysteriously get this compiler error: Since this is an async method, the return expression must be of type 'string' rather than Task<string>

但是后来神秘地得到了这个编译器错误:由于这是一个异步方法,返回表达式必须是“字符串”类型而不是 Task<string>

What am I missing here?

我在这里缺少什么?

采纳答案by Stephen Cleary

You may want to read my async/awaitintro post.

您可能想阅读我的async/await介绍文章

Return values from asyncmethods are wrapped in a Task<TResult>. Likewise, awaitunwraps those return values:

async方法的返回值包装在Task<TResult>. 同样,await解开这些返回值:

public static async Task<String> LongTaskAAsync() {
  await Task.Delay(2000);
  return await Task.Run(() => {
    return("AAA");
  });
}

The reasoning behind this is described in my Async "Why Do the Keywords Work ThatWay" Unofficial FAQ.

这背后的原因在我的异步“为什么关键字以这种方式工作”非官方常见问题解答中有所描述。

P.S. You can also use Task.FromResultfor simple tests like this.

PS 您也可以Task.FromResult用于这样的简单测试。

Edit:If you want to create and return the Taskobject itself, then the method should notbe async. One somewhat common pattern is to have a publicnon-asyncmethod that calls the asyncportion only if necessary.

编辑:如果你想创建并返回Task对象本身,则该方法应该不会async。一种比较常见的模式是有一个publicasync方法,async仅在必要时调用该部分。

For example, some kind of asynchronous cache - if the object is in the cache, then return it immediately; otherwise, asynchronously create it, add it to the cache, and return it (this is example code - not thread-safe):

例如,某种异步缓存——如果对象在缓存中,则立即返回;否则,异步创建它,将它添加到缓存中,然后返回它(这是示例代码 - 不是线程安全的):

public static Task<MyClass> GetAsync(int key)
{
  if (cache.Contains(key))
    return Task.FromResult(cache[key]);
  return CreateAndAddAsync(key);
}

private static async Task<MyClass> CreateAndAddAsync(int key)
{
  var result = await CreateAsync(key);
  cache.Add(key, result);
  return result;
}

回答by GameScripting

Can a “task method” also be an “async” method?

“任务方法”也可以是“异步”方法吗?

Yes it can be, by simply changing the method signature to public async static Task<Task<String>> LongTaskAAsync()since that is, what it will return.

是的,它可以通过简单地将方法签名更改为,public async static Task<Task<String>> LongTaskAAsync()因为它会返回什么。

If you use the asynckeyword, the runtime will wrap the type you return into a task, to enable asynchronousness. Say if you return a string, the runtime will wrap that into a Task<string>. intwill go Task<int>and Task<string>will go Task<Task<string>>. See this console app to clearify:

如果您使用async关键字,运行时会将您返回的类型包装到任务中,以启用异步性。假设您返回 a string,运行时会将其包装到 a 中Task<string>int会去Task<int>Task<string>会去Task<Task<string>>。请参阅此控制台应用程序以清除:

public class Program
{
    public static void Main(string[] args)
    {
        // start the main procedure asynchron
        Task.Run(() => DoIt()).Wait();
    }

    // for async support since the static main method can't be async
    public static async void DoIt()
    {
        Program p = new Program();

        // use the methods
        string s = await p.GetString();
        int i = await p.GetInt();
        Task<string> tsk = await p.GetTaskOfString();

        // just to prove the task works:

        // C# 5
        string resultFromReturnedTask = await tsk;

        // C# 4
        string resultFromReturnedTask2 = tsk.Result;
    }

    public async Task<string> GetString()
    {
        return "string";
    }

    public async Task<int> GetInt()
    {
        return 6;
    }

    public async Task<Task<string>> GetTaskOfString()
    {
        return Task.Run(() => "string");
    }
}