为什么 IMemoryCache.GetOrCreateAsync 返回“TItem”?(可为空)而不是“TItem”?

Luk*_* Vo 10 .net c# memorycache nullable-reference-types

的扩展GetOrCreateAsync方法IMemoryCache

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;
}
Run Code Online (Sandbox Code Playgroud)

为什么他们会回来TItem?而不是仅仅TItem?假设我的factory方法永远不会返回 null,那么可以安全地假设它永远不会返回null并使用 null-forgiving 运算符忽略它!吗?

public async Task<Foo> GetFooAsync()
    => (await cache.GetOrCreateAsync("Foo", async _ => new Foo()))!
Run Code Online (Sandbox Code Playgroud)

小智 9

这篇github 帖子有一些重要因素解释了为什么他们选择将其设为可为 null 的返回类型。这里有一些需要考虑的事情。

根据eerhardt可以缓存空值。

斯蒂芬·托布 (Stephen Toub) 在帖子中指出

我们对核心库中可空注释的首要原则之一是,它们永远不应该撒谎并说空不是可能的结果,而实际上它是可能的。这确实会导致某些情况下方法被注释为返回 T?即使 null 很少见或属于极端情况,例如 Activator.CreateInstance 返回 T?因为例如,如果您指定 Nullable 作为类型,它实际上可以为 null,但这意味着可以信任返回值的可为空性:如果它说它不可为 null,那么它永远不会为 null,并且调用者不会不需要防止取消引用 null。https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/api-guidelines/nullability.md中概述了这些原则。

我希望这能让人们清楚地了解为什么他们选择将其设为可为空。在您的情况下,如果您 100% 确定不会缓存任何可空值,那么理论上您可以忽略它可以返回空值的事实。尽管我不建议在任何情况下使用它,但您的程序会增长/更改并要求这是可能的。