Cache Stores
The reflection cache is partitioned into three independent stores — each holding a different reflection artifact. Every store is a thread-safe ConcurrentDictionary with its own size cap and eviction timeline.
The three stores
| Store | Key | Value | Purpose |
|---|---|---|---|
| TypeProperties | Type | Dictionary<string, PropertyInfo> | All public instance properties per type, keyed by property name for O(1) lookup. |
| PropertyPath | (Type, string) | string | Validated & normalized dotted property paths — e.g. "customer.address.city" → "Customer.Address.City". |
| CollectionElementType | Type | Type? | Element type for recognized collections — arrays plus exactly List<>, ICollection<>, IEnumerable<>, IList<>, HashSet<> and ISet<> — e.g. List<Order> → Order. null for everything else, IReadOnlyList<T> included. |
Note
Each store is identifiable at runtime via the
CacheMemoryType enum: TypeProperties, PropertyPath, and CollectionElementType. Pass that value to ClearCache or IsCacheFull to target a single store.Targeting a specific store
using DynamicWhere.ex.Optimization.Cache.Source;
using DynamicWhere.ex.Optimization.Cache.Enums;
// Clear only the validated-path store, leave property metadata intact
CacheExpose.ClearCache(CacheMemoryType.PropertyPath);
// Check if a single store has hit its cap
bool typesFull = CacheExpose.IsCacheFull(CacheMemoryType.TypeProperties);
bool pathsFull = CacheExpose.IsCacheFull(CacheMemoryType.PropertyPath);
bool collectionsFull = CacheExpose.IsCacheFull(CacheMemoryType.CollectionElementType);Sizing
All three stores share the same MaxCacheSize from your CacheOptions. The cap is a strictly-greater test, evaluated on a miss before the new entry is written, so with the default of 1000 each store settles at 1001 entries — 3003 across the process, and more when misses land concurrently. Increase or decrease this through a preset or a custom options object.
Entry lifetime
- Entries are added on first reflection miss for a given key.
- Entries record an access on read — a timestamp under LRU, a counter under LFU, nothing under FIFO.
EvictionStrategyalone decides which; theEnable*Trackingflags do not. - Under LRU the timestamp is refreshed once it is a second old rather than on every read (3.3.0). Eviction only asks which entries are oldest, and an entry read a moment ago is already among the newest; writing it on every read put every thread reading the same few entries into one queue. A counter under LFU still counts every read.
- Entries are removed only when an eviction pass runs (automatic on overflow, or manual via
ForceEvictionOnAllCaches/ClearCache/ClearAllCaches).