Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 23, 2025

Summary

Fixes the documentation ambiguity in CacheExtensions.TryGetValue<TItem> and CacheExtensions.Get<TItem> to clarify that these methods handle type mismatches by returning false/default(TItem), not just when keys are absent.

Problem

The existing documentation stated that TryGetValue<TItem> returns "true if the key was found; false otherwise", which was ambiguous and misleading. In reality, the method returns false in two distinct scenarios:

  1. When the key doesn't exist in the cache
  2. When the key exists but the stored value can't be cast to TItem

This caused confusion, especially for instrumented cache decorators that track hit/miss metrics:

IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());
cache.Set("key", (object)"string-value");

// Non-generic sees "hit" (returns true because key exists)
cache.TryGetValue("key", out object? obj);  // true

// Generic extension sees "miss" (returns false due to type mismatch)
cache.TryGetValue<int>("key", out var i);   // false

Changes

TryGetValue<TItem> Method

  • Summary: Updated to explicitly mention casting to TItem
  • Returns: Changed to "true if the key was found and the stored value can be cast to TItem; false otherwise"
  • Parameter: Clarified that value is set to default(TItem) for both missing keys and type mismatches
  • Remarks: Added comprehensive guidance explaining:
    • The method returns false for both missing keys and type mismatches
    • Users needing to distinguish these cases (e.g., for instrumentation) should use the non-generic IMemoryCache.TryGetValue method, which returns true if the key exists regardless of type

Get<TItem> Method

  • Summary: Updated to clarify it returns values only when "present and castable to TItem"
  • Returns: Added that default(TItem) is returned for both missing keys and type mismatches

Resolution

Addresses #38969 by providing clear documentation that helps developers understand the type-checking behavior and guides them toward appropriate alternatives when they need to distinguish between "key not found" and "key found with incompatible type" scenarios.

Original prompt

This section details on the original issue you should resolve

<issue_title>CacheExtensions.TryGetValue documentation and behavior are ambiguous for type mismatches (key present with incompatible type returns false)</issue_title>
<issue_description>### Description

When using Microsoft.Extensions.Caching.Memory.IMemoryCache with the generic extension method:

IMemoryCache cache = ...;
cache.Set("k", (object)"string-value");

// Under the hood: IMemoryCache.TryGetValue("k", out object? obj) == true
// But the generic extension below returns false because obj is not int.
bool found = cache.TryGetValue<int>("k", out var i); // found == false

This reveals two problems:

  1. Behavioral ambiguity for instrumentation / decorators
    A decorator that instruments IMemoryCache.TryGetValue(object, out object?) will observe a hit (returns true because the key exists), while the calling code using CacheExtensions.TryGetValue<T> observes a miss (false due to type mismatch). This makes consistent hit/miss accounting impossible when consumers use the generic extension.

  2. Documentation mismatch
    The current docs for CacheExtensions.TryGetValue<T> say: “true if the key was found; false otherwise.” In the scenario above, the key is found but the method returns false. The real behavior is closer to:

“Returns true if the key was found and the stored value is of type TItem (otherwise returns false and sets return value to default).”

Reproduction Steps

using Microsoft.Extensions.Caching.Memory;

var cache = new MemoryCache(new MemoryCacheOptions());

// Store as object/string
cache.Set("key", (object)"abc");

// 1) Non-generic call sees "found"
var foundObj = cache.TryGetValue("key", out object? obj); // true

// 2) Generic extension reports "not found" for incompatible type
var foundInt = cache.TryGetValue<int>("key", out var i);   // false

// Instrumented decorators counting "hits" in IMemoryCache.TryGetValue(object, out object?)
// will count the first as a hit, while callers using the generic extension see a miss.
Console.WriteLine((foundObj, foundInt)); // (True, False)

Expected behavior

Docs and API guidance should clarify that the generic overload only returns true when the value exists and is compatible with TItem.

Expected behavior

  • CacheExtensions.TryGetValue<T> documentation should explicitly state:

"Returns true if the key was found and the stored value can be cast to TItem. Returns false otherwise (including type mismatches)."

  • Guidance should explain implications for decorators/instrumented caches.
  • (Optional stretch) Consider an additional API if presence-vs-type disambiguation is needed, but a doc fix alone would resolve most confusion.

Actual behavior

  • Non-generic IMemoryCache.TryGetValue(object, out object?) returns true if the key is present.
  • Generic CacheExtensions.TryGetValue<T> returns false if the type does not match, even when the key exists.
  • Documentation implies only the first behavior ("true if the key was found”'), without mention of the type check.

Regression?

No. This appears to be the behavior since the generic extension was introduced. The issue is a documentation mismatch and missing guidance rather than a runtime regression

Known Workarounds

  • Use the non-generic overload when consistent hit/miss metrics are required in decorators.
  • Or, after a generic call returns false, double-check with the non-generic overload if you need to distinguish "key present with wrong type" from "key absent" scenario.

Configuration

No response

Other information

No response</issue_description>

<agent_instructions>Please fix the documentation based on the feedback provided in the issue.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@jozkee @rjmurillo thank you for reporting this. Your workaround is correct, and the documentation should be clearer about the type check in the "found" logic.

Fixes #11958


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Fix ambiguity in CacheExtensions.TryGetValue<T> behavior Clarify CacheExtensions.TryGetValue<TItem> documentation for type mismatch behavior Oct 23, 2025
Copilot AI requested a review from jozkee October 23, 2025 19:48
Copilot finished work on behalf of jozkee October 23, 2025 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CacheExtensions.TryGetValue<T> documentation and behavior are ambiguous for type mismatches (key present with incompatible type returns false)

2 participants