为了异步运行代码(例如使用async/await),我需要一个合适的Task。当然,框架中有几个预定义的方法,涵盖了最频繁的操作,但有时我想写自己的方法。我是C#的新手,所以很可能我做错了,但我至少对目前的做法不太满意。关于我正在做的事情,请参阅以下示例:
public async Task<bool> doHeavyWork()
{
var b1 = await this.Foo();
//var b2 = await Task<bool>.Factory.StartNew(Bar); //using Task.Run
var b2 = await Task.Run(()=>Bar());
return b1 & b2;
}
public Task<bool> Foo()
{
return Task.Factory.StartNew(() =>
{
//do a lot of work without awaiting
//any other Task
return false;
});
}
public bool Bar()
{
//do a lot of work without awaiting any other task
return false;
}
一般来说,我创建和使用像Foo示例这样的方法,但有一个"额外"lambda包含整个方法逻辑,看起来不是很漂亮。另一种选择是使用任何类似Bar示例的方法,但我认为这更糟,因为不清楚该方法是否应该异步运行(除了BarAsync等正确的方法名称),并且Task.Factory.StartNew可能必须在程序中重复多次。我不知道如何告诉编译器"这个方法返回一个任务,请在调用时将其作为一个整体包装成一个任务",这就是我想要做的。
最后我的问题是:写这样一个方法最好的方法是什么?我可以去掉"extra"lambda吗(当然不添加额外的命名方法)?
编辑正如Servy所说,总是有充分的理由拥有该方法的同步版本。只有在绝对必要的情况下才应该提供异步版本(Stephen Cleary的链接)。
如果有人想调用Bar
而不在新线程/任务中启动它,世界会结束吗?如果有另一个方法已经在后台线程中,所以它不需要启动新任务来运行长时间运行的代码,该怎么办?如果该方法最终被重构为从桌面应用程序上下文以及ASP或控制台上下文调用的类库,该怎么办?在其他情况下,该方法可能只需要直接运行,而不是作为Task
运行。
我想说,您的代码应该像Bar
那样,除非在任何情况下都必须在不启动新的Task
的情况下运行该代码。
还要注意,对于较新版本的.NET,您应该从Task.Factory.StartNew
切换到Task.Run
,因此代码量应该会减少(有点)。