如何正确实现一个平台具有同步代码而另一个平台具有异步代码的 DependencyService

时间:2021-02-10 12:40:11

标签: c# xamarin asynchronous xamarin.forms

我有 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()' 上运行代码会更好吗?

2 个答案:

答案 0 :(得分:2)

我建议忽略带有 #pragma 的警告。该警告是为了通知您您可能忘记了 await,但由于您知道代码是同步的,您可以放心地忽略该警告。

如果你必须多次这样做,你可以使用像 this 这样的辅助方法来只忽略一个地方的警告。用法:

public Task FooAsync() => TaskHelper.ExecuteAsTask(() =>
{
    DoSomething();
});

如果您确实使用了 Task.FromResultTask.CompletedTask,您还应该将同步代码包装在 try/catch 中并返回 Task.FromException(如果有)例外。预计 Task-returning 方法将在返回的任务上放置异常而不是直接抛出它们。

答案 1 :(得分:1)

我认为您必须保持两者异步,因为其中之一需要它。以下是如何让它更干净。

通过返回 Task.CompletedTask,您看起来好像完成了一些异步工作并且已经完成,从而使其“更干净”。

如果您对为什么返回 Task.CompletedTask 是个好主意感兴趣,请查看 this post

public class MyiOSImplementation : IMyInterface
{
    public Task FooAsync()
    {
        DoSomething();
        return Task.CompletedTask;
    }
}