为何IMemoryCache.GetOrCreateAsync返回TItem?而非TItem?使用!是否安全?
关于IMemoryCache扩展方法GetOrCreateAsync的疑问
扩展方法定义
public static async Task<TItem?> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory) { if (!cache.TryGetValue(key, out object? result)) { using ICacheEntry entry = cache.CreateEntry(key); result = await factory(entry).ConfigureAwait(false); entry.Value = result; } return (TItem?)result; }
疑问1:为什么方法返回TItem?而非TItem?
原因主要有两点:
- 缓存允许存储null值:IMemoryCache本身支持将null作为有效值存入缓存。如果之前有代码通过这个key存入了null,
cache.TryGetValue会成功取出null,此时方法返回的就是null。 - 兼容泛型的null场景:方法的泛型签名没有限制
TItem不能为null(比如TItem是引用类型时,本身就允许为null)。返回TItem?是为了覆盖所有可能的null情况,符合C#可空引用类型的规范。
疑问2:若factory从不返回null,是否可以安全使用空原谅运算符!?
如果能同时满足以下两个条件,使用!是安全的:
- 你的
factory方法绝对不会返回null,包括后续代码迭代中也不会出现返回null的情况。 - 该缓存key永远不会被存入null值——不管是自己的代码还是其他模块的代码,都不会往这个key写入null。
但要注意:一旦有代码往这个缓存key存入了null,或者factory意外返回null,使用!会直接触发NullReferenceException。如果无法完全控制缓存写入逻辑和factory的实现,这种写法就存在风险。
示例代码
public async Task<Foo> GetFooAsync() => (await cache.GetOrCreateAsync("Foo", async _ => new Foo()))!
内容的提问来源于stack exchange,提问作者Luke Vo
相关产品推荐
相关产品推荐

