问题描述
我有 Xamarin.Forms 项目,使用 Android、iOS 和 UWP 的平台特定代码实现 DependencyService。我使用几个异步方法为 DependencyService 创建了接口。对于某些平台,特定于平台的代码是异步的,而对于其他平台则是同步的。
假设我在 Xamarin.Forms 项目中有一个接口:
public interface IMyInterface
{
Task FooAsync();
}
IMyInteface 的 Android 实现:
public class MyAndroidImplementation : IMyInterface
{
public async Task FooAsync()
{
await DoSomethingAsync();
}
}
IMyInterface 的 iOS 实现:
public class MyiOSImplementation : IMyInterface
{
public async Task FooAsync()
{
DoSomething();
}
}
iOS 实现中只有同步代码。这会引发警告消息:
此异步方法缺少“await”运算符,将同步运行。 考虑使用 'await' 运算符来等待非阻塞 API 调用, 或 'await Task.Run(...)' 在后台线程上执行 cpu 密集型工作。
处理这种情况的正确方法是什么?
我不喜欢将同步代码包装到异步“await Task.Run()”中,因为这显然是存在异步代码的谎言。使用 void 方法设计 IMyInterface 然后在特定于平台的实现中在 'Task.Run()' 上运行代码会更好吗?
解决方法
我建议忽略带有 #pragma
的警告。该警告是为了通知您您可能忘记了 await
,但由于您知道代码是同步的,您可以放心地忽略该警告。
如果你必须多次这样做,你可以使用像 this 这样的辅助方法来只忽略一个地方的警告。用法:
public Task FooAsync() => TaskHelper.ExecuteAsTask(() =>
{
DoSomething();
});
如果您确实使用了 Task.FromResult
或 Task.CompletedTask
,您还应该将同步代码包装在 try
/catch
中并返回 Task.FromException
(如果有)例外。预计 Task
-returning 方法将在返回的任务上放置异常而不是直接抛出它们。
我认为您必须保持两者异步,因为其中之一需要它。以下是如何让它更干净。
通过返回 Task.CompletedTask
,您看起来好像完成了一些异步工作并且已经完成,从而使其“更干净”。
如果您对为什么返回 Task.CompletedTask
是个好主意感兴趣,请查看 this post
public class MyiOSImplementation : IMyInterface
{
public Task FooAsync()
{
DoSomething();
return Task.CompletedTask;
}
}