我正在重写一个必须调用数据库服务器的Windows Forms app.调用可能需要长达30秒的时间,所以我想缓存结果(它不会改变).

如何,多个事件可以触发对此信息的需求,这取决于在UI中输入或 Select 了哪些其他信息.可能需要该信息的不同UI组件彼此不知道.

我只想调用那个数据库一次.所以,如果你,作为用户,触发了30秒的数据库调用(这是异步完成的),然后5秒后应用程序的另一部分发现需要该信息,我不希望应用程序发出另一个数据库请求,仅仅因为缓存仍然是空的.我希望它等待剩下的25秒,直到信息变得可用,获取缓存值,然后返回.

但我不能完全理解如何构建它,无论是数据还是代码.

我认为这个场景是两个(或更多)请求,它们以某种方式排队,一旦第一个请求被DB调用满足,第二个请求就获得现在缓存的结果值并返回.如果稍后有其他东西--第三件事--需要此信息,则请求将获取缓存值并立即返回.

我想知道在.NET中是否有这样做的内置模式或数据 struct 集.我觉得这几乎是--但不完全是--基本的async/await模式,只是有多个东西在等待相同的结果.

这是什么模式/架构,我正在考虑,但不能完全可视化??

推荐答案

多件事情等待相同结果的模式就是...多件事情等待着同一项任务.就这样.根本没有什么魔力.

.NET的Task可以等待多次,没有问题,并无限期地存储他们的结果(这与ValueTask不同,ValueTask只能等待一次).如果你等待一个已经完成的任务,它会立即返回结果.因此,您可以只缓存任务,而不是缓存结果.

记住这一点,只需简单地引用任务本身.

private async Task<YourDatabaseResult> RunQueryInternal()
{
    // do the actual database query here
}

private Task<YourDatabaseResult>? _task;

public Task<YourDatabaseResult> RunQuery()
{
    if (_task == null)
        _task = RunQueryInternal();
    return _task;
}

第一次调用该方法时,查询被触发,任务被存储.后续调用只返回相同的任务,因此每个人都会等待它,而查询实际上只执行一次.

现在,这有点幼稚,因为它不处理任何错误.但这应该足以让你开始.

.net相关问答推荐

如何查询 DOTNET_CLI_TELEMETRY_OPTOUT 是否永久设置为 TRUE?

无法加载文件或程序集 不支持操作. (来自 HRESULT 的异常:0x80131515)

从 byte[] 创建 zip 文件

为什么 StyleCop 建议在方法或属性调用前加上this?

如何在 C# 中创建表达式树来表示String.Contains("term")?

防止对话框在按钮的单击事件处理程序中关闭

如何从 appsettings.json 中获取价值

共享 AssemblyInfo 用于跨解决方案的统一版本控制

如何以编程方式 Select ListView 中的项目?

实体框架无法加载指定的元数据资源

如何使用反射在 .NET 中调用重载方法

何时在 C#/.NET 中使用指针?

WCF反序列化如何在不调用构造函数的情况下实例化对象?

我不了解应用程序域

如何允许程序集(单元测试)访问另一个程序集的内部属性?

从 C# 中的字符串中删除最后一个字符.优雅的方式?

如何找到二维数组的大小?

WebClient.DownloadString 由于编码问题导致字符损坏,但浏览器正常

在不使用while循环的情况下找到最里面的异常?

如何将 MailMessage 对象作为 *.eml 或 *.msg 文件保存到磁盘