C# 返回已完成任务的最佳方式是什么?

C# 返回已完成任务的最佳方式是什么?,c#,.net,task-parallel-library,.net-4.5,c#-5.0,C#,.net,Task Parallel Library,.net 4.5,C# 5.0,返回已完成对象的最佳方式是什么 可以写,或者别的什么 但是什么是最有效的方法呢?斯蒂芬·图布(MSFT)的回答: 如果每次都需要一个新的Task对象,则Task.FromResult是最有用的 有效率的当前实现中的Task.Delay(0)将返回 缓存任务,但这是一个实现细节。如果你想用 对于缓存的任务,您应该自己缓存一个,例如private static 只读任务s_completedTask=Task.FromResult(true);然后使用 s_完成了任务 Task.FromResult

返回已完成对象的最佳方式是什么

可以写,或者别的什么

但是什么是最有效的方法呢?

斯蒂芬·图布(MSFT)的回答:

如果每次都需要一个新的Task对象,则Task.FromResult是最有用的 有效率的当前实现中的Task.Delay(0)将返回 缓存任务,但这是一个实现细节。如果你想用 对于缓存的任务,您应该自己缓存一个,例如private static 只读任务s_completedTask=Task.FromResult(true);然后使用 s_完成了任务


Task.FromResult将是最直接的。它还包括一些常见整数等的内置结果。但是,如果您的值不是“明显”值(并且没有内置处理),但在您的场景中可能会经常返回-那么您可以在字段中创建自己的缓存结果(如果合适,可能是静态的)-但缓存任务很重要,不是结果本身。l-否则每次只使用Task.FromResult。

这里有一个小演示,展示了标记为异步的方法和未标记为异步的方法在异常处理方面的差异

public Task<string> GetToken1WithoutAsync() => throw new Exception("Ex1!");

// Warning: This async method lacks 'await' operators and will run synchronously. Consider ...
public async Task<string> GetToken2WithAsync() => throw new Exception("Ex2!");  

public string GetToken3Throws() => throw new Exception("Ex3!");
public async Task<string> GetToken3WithAsync() => await Task.Run(GetToken3Throws);

public async Task<string> GetToken4WithAsync() { throw new Exception("Ex4!"); return await Task.FromResult("X");} 


public static async Task Main(string[] args)
{
    var p = new Program();

    try { var task1 = p.GetToken1WithoutAsync(); } 
    catch( Exception ) { Console.WriteLine("Throws before await.");};

    var task2 = p.GetToken2WithAsync(); // Does not throw;
    try { var token2 = await task2; } 
    catch( Exception ) { Console.WriteLine("Throws on await.");};

    var task3 = p.GetToken3WithAsync(); // Does not throw;
    try { var token3 = await task3; } 
    catch( Exception ) { Console.WriteLine("Throws on await.");};

    var task4 = p.GetToken4WithAsync(); // Does not throw;
    try { var token4 = await task4; } 
    catch( Exception ) { Console.WriteLine("Throws on await.");};
}

从移动(并编辑)

这是什么原因?你不需要为这个任务。只需调用该方法。@I4V当操作有时需要工作,但有时不需要工作时,这是一种常见做法,并且可以在不需要异步的情况下高效地完成。这是一篇关于类似这样的边缘情况的好文章:。tl;dr保留警告是可以的,因为这种方法将避免删除
async
关键字的许多陷阱。“尝试使用return Task.FromResult(mockToken);给出:error CS4016”--这就是为什么在您仅返回任务对象时不使用
async
方法的原因。您的问题中存在缺陷。您说过“当接口需要异步任务时”,但接口永远不能要求
async
。它只能要求返回值为
Task
?谷歌不会返回任何搜索你引用的短语的结果。我直接问他,并将答案发布在这里,因为我认为重要的是,如果
Guid.NewGuid().ToString()
抛出
Guid.NewGuid().ToString(),它将改变
GetToken()
的行为
不会抛出。即使它确实抛出了,我觉得这并不重要:确切的异常行为会有所不同,但不会以任何实质性的方式。无论哪种情况,调用方都会看到异常;在上面的示例中,它将在调用
GetToken()
时使用,而如果该方法保持为
async
,则它将在
wait
上使用。坦率地说,前者更好;失败很快。我只是指出,在某些情况下,这个建议不会产生完全相同的行为。了解
GetToken()
是否可以同步抛出异常,或者是否总是返回
任务
,对于用户从这个答案推断是一个重要的考虑因素。@PatrickRoberts这是一个公平且重要的观点。我添加了一个小演示,以展示您带来的关注;)
// .NETCoreApp,Version=v3.0
Throws before await.
Throws on await.
Throws on await.
Throws on await.