gpt4 book ai didi

c# - 如何处理在一个平台上同步但在另一个平台上异步的代码

转载 作者:太空宇宙 更新时间:2023-11-03 23:06:07 25 4
gpt4 key购买 nike

在编写基于 Xamarin 的跨平台 C# 应用程序时,我经常遇到的一种情况是代码在一个平台上是同步的,但在另一个平台上是异步的。例如,文件访问在 iOS、Android 和 Mac 上是同步的,但在 Windows 上是异步的。

这会导致一些棘手的问题。首先,在纯编码级别上,编译器希望方法是异步的或非异步的。

但比这更糟。例如,如果 iOS UI 线程发现它需要加载一个小文件,并在 UI 线程上同步加载,这可能不会给用户带来任何明显的问题。是的,我知道作为一般规则,人们希望预加载此类资源。但如果没有发生这种情况,并且文件很小,也不会造成问题。

但是如果从 iOS UI 代码调用 C# 异步方法并等待结果,应用程序将挂起。

结果是我们有两个方法,Foo() 和 FooAsync(),我们调用哪一个取决于平台。但我们不能只是让整个事情异步。

鉴于此,如何组织代码以尽可能坚持 DRY,同时在一个平台上保持同步而在另一个平台上保持异步?

**

编辑——响应示例请求:这里是一些说明问题的虚拟代码。如果有人打电话

 await StringLoaders.ReadAllText(somePath) 

从 iOS UI 线程,结果是挂起。是的,这个特定示例有变通方法。但一般问题是反复出现的问题。如果应用程序有很多层,这尤其糟糕,就像这个应用程序一样——可能需要在整个代码中进行同步/异步区分,从而导致大量方法的两个版本。

public class AsyncStringLoader
{
public async Task<string> ReadAllTextAsync(string path) {
return await Task.Run(() => "Hello");
}
}
public class StringLoader {
public string ReadAllText(string path) {
return "Hello";
}
}
public static class StringLoaders {
public static object Current { get; set;} // already trouble here -- we can't really have a proper interface for ReadAllText.
public static async Task<string> ReadAllText(string path) {
object loader = StringLoaders.Current;
if (loader is StringLoader) {
return ((StringLoader)loader).ReadAllText(path);
} else if (loader is AsyncStringLoader) {
return await ((AsyncStringLoader)loader).ReadAllTextAsync(path); // DRY violation, in addition to the hang
} else {
throw new Exception("Unknown loader!");
}
}
}

如果您想要一个真实的示例,而不是一个虚构的示例,请从 NuGet 下载 PCLStorage 库,然后尝试将它用于从 iOS UI 线程调用的任何内容。 . .

最佳答案

您可以在顶层定义一个接口(interface)(或一组接口(interface)),该接口(interface)仅包含异步方法以保持一致性。此顶级接口(interface)将由您的更高级别的应用程序/UI 代码使用,因此更高级别的代码将将该接口(interface)对象作为依赖项。在该接口(interface)下,每个操作系统类型实现 C# 适配器,实现异步接口(interface)方法。对于 Windows,您可以直接使用 native 异步 Windows api。对于其他不提供 async api 的操作系统,使用它们的 sync 方法,但返回一个可等待的任务对象,该对象包装了已经计算好的结果,如下所示:

return Task.FromResult(/*the result of the sync api call from iOS*/);

使用接口(interface)的更高级别代码将只等待接口(interface)的异步方法,而不用关心下面的实现。如果底层实现是 iOS,调用将同步运行,就像您直接调用同步方法一样。如果底层实现是 Windows,异步方法将运行。

我建议接口(interface)全部采用异步方法(相对于所有同步)的原因是,让同步调用看起来像异步(通过 Task.FromResult)比强制异步调用同步工作更安全,后者会导致死锁。另一个原因是,显然您希望尽可能多地利用异步 api 至少对于提供异步方法的操作系统。

您可以根据配置参数等决定在运行时将接口(interface)的哪个实际具体实现(即 Windows、IOS 等)传递给更高级别的代码。您也可以使用现有的一种用于将具体类注册到接口(interface)的依赖注入(inject)容器。

您的问题有点开放性,所以如果您正在寻找其他问题,请提供更多详细信息。

关于c# - 如何处理在一个平台上同步但在另一个平台上异步的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41097901/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com