Redis Cache-Aside模式代码问题:为何需双重await才能编译?
问题根源分析
你遇到的await await问题,核心是泛型参数的类型推断错误:
- 你的
FetchMessage方法返回Task<Message>,而ResultFromCache的fromSource参数定义为Func<T2, T1>,编译器会把T1推断为Task<Message> - 这导致
ResultFromCache的返回值变成了Task<Task<Message>>,必须用两次await才能拿到最终的Message对象
解决方案
修改BaseService中的ResultFromCache方法,让它支持异步数据源委托,同时正确处理异步调用:
修改后的完整代码
using StackExchange.Redis; using System.Text.Json; namespace TestCache { public class Service: BaseService { private Context context { get; } // 修改后:只需一次await public async Task<Message> GetMessage(int accountId) { return await ResultFromCache(accountId, FetchMessage, "Message"); } private async Task<Message> FetchMessage(int parentId) { // 补全EF查询示例 return await context.Message.FirstOrDefaultAsync(m => m.AccountId == parentId); } } public class BaseService { private const int Hour = 3600; private ConnectionMultiplexer connection; private IDatabaseAsync database; // 关键修改:fromSource改为异步委托类型 public async Task<T1> ResultFromCache<T1, T2>(T2 param1, Func<T2, Task<T1>> fromSource, string cacheKey, int cacheDuration = Hour) { // 从缓存获取数据 var result = await CacheGet<T1>(cacheKey); if (result != null) return result; // 从数据库异步获取数据 result = await fromSource(param1); // 补全缓存写入逻辑 if (result != null) { var json = JsonSerializer.Serialize(result); await database.StringSetAsync(cacheKey, json, TimeSpan.FromSeconds(cacheDuration)); } return result; } public async Task<T> CacheGet<T>(string key) { var value = await database.StringGetAsync(key); if (value.IsNull) { return default; } return JsonSerializer.Deserialize<T>(value); } } }
关键修改点说明
- 委托类型调整:将
Func<T2, T1>改为Func<T2, Task<T1>>,明确接受返回Task<T1>的异步方法,避免泛型类型推断错误 - 异步调用处理:调用
fromSource(param1)时加上await,直接拿到T1类型的结果,消除嵌套的Task包装 - 补全缓存写入:完善了原代码的TODO部分,实现Cache-Aside模式的完整流程,确保数据库查询结果能正确存入缓存
修改后,业务方法只需一次await即可正常编译运行,使用者无需再写await await。
内容的提问来源于stack exchange,提问作者RichardAZ
相关产品推荐
相关产品推荐

