The extension method GetOrCreateAsync
for 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;
}
Why do they returns TItem?
instead of just TItem
? Assuming my factory
method never returns null, is it safe to assume it would never be null
and just ignore it with null-forgiving operator !
?
public async Task<Foo> GetFooAsync()
=> (await cache.GetOrCreateAsync("Foo", async _ => new Foo()))!
CodePudding user response:
This github post has some important factors as to why they chose to make it a nullable return type. Here are a couple things to consider.
It is possible to cache a null value according to eerhardt.
In the post Stephen Toub states the following:
One of our overarching principles for nullable annotations in the core libraries it that they should never lie and say null isn't a possible result when in fact it is. This does lead to some cases where a method is annotated as returning a T? even if null is rare or relegated to a corner-case, e.g. Activator.CreateInstance returns T? because for example it can actually be null if you specify a Nullable as the type, but it means the nullability of the return value can be trusted: if it says it's non-nullable, then it won't ever be null, and callers don't need to guard against dereferencing null. The principles are outlined in https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/api-guidelines/nullability.md.
I hope this gives a clear idea why they chose to make it nullable. In your case if you are 100% sure that you won't cache any nullables you could in theory ignore the fact that it can return a null value. Although I don't recommend it in any case you program grows/ changes and requires this to be possible.