To clarify Michael Petrotta's accepted answer a bit (too long for a comment, I'm afraid), the concrete implementations of CacheInternal (CacheSingle and CacheMultiple, the latter of which merely manages multiple instances of the former), which is what's utilized internally by the public Cache type to support its Get, Add, Insert, etc. methods, do rely on a HashTable for storage. However, there's never any question of whether there is or isn't a value for a particular key in the HashTable, because the native (cached) values aren't stored in the HashTable directly. Instead, the HashTable is filled with unique CacheEntry objects that wrap the cached keys and values (CacheEntry actually derives from CacheKey, adding an Object-based Value property, among other things; the non-null value requirement can be found in its constructor).
Based on my reading of the code, there's no obvious technical reason for the authors to have required a non-null CacheEntry.Value, except that the public Cache object doesn't expose a Contains- or Exists-type method, and of course doesn't expose the internal underlying CacheEntry objects, it only returns the CacheEntry values. So, as per Michael's answer, without forcing values to be non-null it isn't possible for Cache object users to know whether a particular key value exists. It's also possible, but would require more code reading to know for sure, that the rather complex approach taken internally to manage cached object dependencies, expirations, events, and in-place updates of HashTable entries might rely, in some way, on the values being non-null.