Skip to content

Commit 916600a

Browse files
committed
Add documentation
1 parent 9cec4ea commit 916600a

File tree

10 files changed

+186
-2
lines changed

10 files changed

+186
-2
lines changed

AsyncMemoryCache/AsyncMemoryCache.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.Logging;
1+
using AsyncMemoryCache.EvictionBehaviors;
2+
using Microsoft.Extensions.Logging;
23
using Microsoft.Extensions.Logging.Abstractions;
34
using Nito.AsyncEx;
45
using System;
@@ -10,16 +11,58 @@
1011

1112
namespace AsyncMemoryCache;
1213

14+
/// <summary>
15+
/// This interface exists mainly to avoid having concrete types as constructor arguments.
16+
/// An effect of this is enabling subsitution and as a result, easier testing, where an actual concrete instance is not required in each and every test that uses a class that looks like the following
17+
/// <para/>
18+
/// <code>
19+
/// public MyService(AsyncMemoryCache&lt;string, SomeCacheable&gt;) { }
20+
/// </code>
21+
/// </summary>
22+
/// <typeparam name="TKey">The type of the key for cache items represented by the cache.</typeparam>
23+
/// <typeparam name="TValue">The type of the value which each item in the cache will hold.</typeparam>
1324
public interface IAsyncMemoryCache<TKey, TValue>
1425
where TKey : notnull
1526
where TValue : IAsyncDisposable
1627
{
28+
/// <summary>
29+
/// Gets the cached item with the specified key.
30+
/// </summary>
31+
/// <param name="key">The key of the element to get.</param>
32+
/// <returns>A <see cref="CacheEntityReference{TKey, TValue}"/> representing the lifetime of the underlying <see cref="CacheEntity{TKey, TValue}"/> until disposed.</returns>
1733
CacheEntityReference<TKey, TValue> this[TKey key] { get; }
34+
35+
/// <summary>
36+
/// Gets the value associated with this key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.<br/>
37+
/// The <paramref name="objectFactory"/> is started in a non-blocking fashion, and the result from it will have to be <c>await</c>ed
38+
/// </summary>
39+
/// <param name="key">The cache item key.</param>
40+
/// <param name="objectFactory">The object factory.</param>
41+
/// <param name="lazyFlags">Optional <see cref="AsyncLazyFlags"/> to configure object factory behavior.</param>
42+
/// <returns>A <see cref="CacheEntityReference{TKey, TValue}"/> representing the lifetime of the underlying <see cref="CacheEntity{TKey, TValue}"/> until disposed.</returns>
1843
CacheEntityReference<TKey, TValue> GetOrCreate(TKey key, Func<Task<TValue>> objectFactory, AsyncLazyFlags lazyFlags = AsyncLazyFlags.None);
44+
45+
/// <summary>
46+
/// Determines whether the <see cref="IAsyncMemoryCache{TKey, TValue}"/> contains an element with the specified key.
47+
/// </summary>
48+
/// <param name="key">The key to locate in the <see cref="IAsyncMemoryCache{TKey, TValue}"/>.</param>
49+
/// <returns><see langword="true"/> if the <see cref="IAsyncMemoryCache{TKey, TValue}"/> contains a cache item with the key; otherwise, <see langword="false"/>.</returns>
1950
bool ContainsKey(TKey key);
51+
52+
/// <summary>
53+
/// Gets the value associated with the specified key.
54+
/// </summary>
55+
/// <param name="key">The key whose value to get.</param>
56+
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter.</param>
57+
/// <returns><see langword="true"/> if a cache item with the specified key exists; otherwise <see langword="false"/>.</returns>
2058
bool TryGetValue(TKey key, [NotNullWhen(true)] out CacheEntityReference<TKey, TValue>? value);
2159
}
2260

61+
/// <summary>
62+
/// The default implementation of <see cref="IAsyncMemoryCache{TKey, TValue}"/>
63+
/// </summary>
64+
/// <typeparam name="TKey">The type of the key for cache items represented by the cache.</typeparam>
65+
/// <typeparam name="TValue">The type of the value which each item in the cache will hold.</typeparam>
2366
public sealed class AsyncMemoryCache<TKey, TValue> : IAsyncDisposable, IAsyncMemoryCache<TKey, TValue>
2467
where TKey : notnull
2568
where TValue : IAsyncDisposable
@@ -44,6 +87,7 @@ public AsyncMemoryCache(IAsyncMemoryCacheConfiguration<TKey, TValue> configurati
4487
configuration.EvictionBehavior.Start(configuration, _logger);
4588
}
4689

90+
/// <inheritdoc/>
4791
public CacheEntityReference<TKey, TValue> this[TKey key]
4892
{
4993
get
@@ -54,6 +98,7 @@ public CacheEntityReference<TKey, TValue> this[TKey key]
5498
}
5599
}
56100

101+
/// <inheritdoc/>
57102
public CacheEntityReference<TKey, TValue> GetOrCreate(TKey key, Func<Task<TValue>> objectFactory, AsyncLazyFlags lazyFlags = AsyncLazyFlags.None)
58103
{
59104
_logger.LogTrace("Adding item with key: {Key}", key);
@@ -69,9 +114,11 @@ public CacheEntityReference<TKey, TValue> GetOrCreate(TKey key, Func<Task<TValue
69114
return new(cacheEntity);
70115
}
71116

117+
/// <inheritdoc/>
72118
public bool ContainsKey(TKey key)
73119
=> _cache.ContainsKey(key);
74120

121+
/// <inheritdoc/>
75122
public bool TryGetValue(TKey key, [NotNullWhen(true)] out CacheEntityReference<TKey, TValue>? value)
76123
{
77124
if (_cache.TryGetValue(key, out var entity))

AsyncMemoryCache/AsyncMemoryCacheConfiguration.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,43 @@
66

77
namespace AsyncMemoryCache;
88

9+
/// <summary>
10+
/// An interface which configures the <see cref="AsyncMemoryCache{TKey, TValue}"/><br/>
11+
/// Can be used to extend the configuration for use in custom implementations of either <see cref="IAsyncMemoryCache{TKey, TValue}"/> or <see cref="IEvictionBehavior"/>
12+
/// </summary>
13+
/// <typeparam name="TKey">The type of the key for cache items represented by the cache.</typeparam>
14+
/// <typeparam name="TValue">The type of the value which each item in the cache will hold.</typeparam>
915
public interface IAsyncMemoryCacheConfiguration<TKey, TValue>
1016
where TKey : notnull
1117
where TValue : IAsyncDisposable
1218
{
1319
Action<TKey, TValue>? CacheItemExpired { get; init; }
20+
21+
/// <summary>
22+
/// The eviction behavior. Default is <see cref="DefaultEvictionBehavior"/>
23+
/// </summary>
1424
IEvictionBehavior EvictionBehavior { get; init; }
25+
26+
/// <summary>
27+
/// The cache backing store. Default is <see cref="ConcurrentDictionary{TKey, TValue}"/>.
28+
/// </summary>
1529
IDictionary<TKey, CacheEntity<TKey, TValue>> CacheBackingStore { get; init; }
1630
}
1731

32+
/// <summary>
33+
/// The default implementation of <see cref="IAsyncMemoryCacheConfiguration{TKey, TValue}"/>
34+
/// </summary>
35+
/// <typeparam name="TKey">The type of the key for cache items represented by the cache.</typeparam>
36+
/// <typeparam name="TValue">The type of the value which each item in the cache will hold.</typeparam>
1837
public sealed class AsyncMemoryCacheConfiguration<TKey, TValue> : IAsyncMemoryCacheConfiguration<TKey, TValue>
1938
where TKey : notnull
2039
where TValue : IAsyncDisposable
2140
{
2241
public Action<TKey, TValue>? CacheItemExpired { get; init; }
42+
43+
/// <inheritdoc/>
2344
public IEvictionBehavior EvictionBehavior { get; init; } = Default;
45+
46+
/// <inheritdoc/>
2447
public IDictionary<TKey, CacheEntity<TKey, TValue>> CacheBackingStore { get; init; } = new ConcurrentDictionary<TKey, CacheEntity<TKey, TValue>>();
2548
}

AsyncMemoryCache/CacheEntity.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
namespace AsyncMemoryCache;
77

8+
/// <summary>
9+
/// Wraps the cached object together with its configured expiration strategy and callbacks.
10+
/// </summary>
11+
/// <typeparam name="TKey">The type of the key used for the item.</typeparam>
12+
/// <typeparam name="TValue">The type of the value which the <see cref="CacheEntity{TKey, TValue}"/> wraps.</typeparam>
813
public sealed class CacheEntity<TKey, TValue>
914
where TKey : notnull
1015
where TValue : IAsyncDisposable
@@ -23,24 +28,48 @@ public CacheEntity(TKey key, Func<Task<TValue>> objectFactory, AsyncLazyFlags la
2328
internal IExpirationStrategy? ExpirationStrategy { get; private set; }
2429
internal Action<TKey, TValue>? ExpirationCallback { get; private set; }
2530

31+
/// <summary>
32+
/// Sets the <see cref="ExpirationStrategy"/> to a new instance of <see cref="AbsoluteExpirationStrategy"/>.<br/>
33+
/// This strategy takes an absolute date into account when evaluating whether or not it is expired.<br/>
34+
/// Useful when more control over the lifetime of a <see cref="CacheEntity{TKey, TValue}"/> is desirable or when there are downsides to having the object alive for an indeterminate amount of time.<br/>
35+
/// </summary>
36+
/// <param name="expiryDate">The configurable exact date used when evaluating if the object should be expired.</param>
37+
/// <returns><see langword="this"/> to enable chained calls</returns>
2638
public CacheEntity<TKey, TValue> WithAbsoluteExpiration(DateTimeOffset expiryDate)
2739
{
2840
ExpirationStrategy = new AbsoluteExpirationStrategy(expiryDate);
2941
return this;
3042
}
3143

44+
/// <summary>
45+
/// Sets the <see cref="ExpirationStrategy"/> to a new instance of <see cref="SlidingExpirationStrategy"/>.<br/>
46+
/// This strategy takes the last use of a <see cref="CacheEntity{TKey, TValue}"/> into account when evaluating whether or not it is expired.<br/>
47+
/// Useful when a cached object is actively used and there is no apparent downside in keeping the cached object alive for an indeterminate amount of time.<br/>
48+
/// </summary>
49+
/// <param name="slidingExpirationWindow">The configurable window used when evaluating if the object should be expired.</param>
50+
/// <returns><see langword="this"/> to enable chained calls</returns>
3251
public CacheEntity<TKey, TValue> WithSlidingExpiration(TimeSpan slidingExpirationWindow)
3352
{
3453
ExpirationStrategy = new SlidingExpirationStrategy(slidingExpirationWindow);
3554
return this;
3655
}
3756

57+
/// <summary>
58+
/// Sets the <see cref="ExpirationStrategy"/> to the provided instance of a custom implementation of <see cref="IExpirationStrategy"/>.<br/>
59+
/// </summary>
60+
/// <param name="expirationStrategy">The custom implementation instance of <see cref="IExpirationStrategy"/></param>
61+
/// <returns><see langword="this"/> to enable chained calls</returns>
3862
public CacheEntity<TKey, TValue> WithExpirationStrategy(IExpirationStrategy expirationStrategy)
3963
{
4064
ExpirationStrategy = expirationStrategy;
4165
return this;
4266
}
4367

68+
/// <summary>
69+
/// Configures the <see cref="ExpirationCallback"/><br/>
70+
/// </summary>
71+
/// <param name="expirationCallback">The callback which will be invoked when this instance of <see cref="CacheEntity{TKey, TValue}"/> expires.</param>
72+
/// <returns><see langword="this"/> to enable chained calls</returns>
4473
public CacheEntity<TKey, TValue> WithExpirationCallback(Action<TKey, TValue> expirationCallback)
4574
{
4675
ExpirationCallback = expirationCallback;

AsyncMemoryCache/CacheEntityReference.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
using System;
1+
using AsyncMemoryCache.EvictionBehaviors;
2+
using System;
23
using System.Diagnostics.CodeAnalysis;
34
using System.Threading;
45

56
namespace AsyncMemoryCache;
67

8+
/// <summary>
9+
/// A class representing the lifetime of the underlying cached object.<br/>
10+
/// As long as this object is referenced/not disposed the cached object will not be evicted or disposed if <see cref="DefaultEvictionBehavior"/> is used.<br/>
11+
/// </summary>
12+
/// <typeparam name="TKey">The type of the key for the cache item.</typeparam>
13+
/// <typeparam name="TValue">The type of the value which the referenced <see cref="CacheEntity{TKey, TValue}"/> wraps.</typeparam>
714
public sealed class CacheEntityReference<TKey, TValue> : IDisposable
815
where TKey : notnull
916
where TValue : IAsyncDisposable

AsyncMemoryCache/EvictionBehaviors/DefaultEvictionBehavior.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
namespace AsyncMemoryCache.EvictionBehaviors;
88

9+
/// <summary>
10+
/// The default provided <see cref="IEvictionBehavior"/>.
11+
/// This class perodically checks for expired items and evicts them. Handling disposal and eviction callbacks as needed.
12+
/// <para/>
13+
/// If a cache entity is considered to be expired but still has a live reference via a <see cref="CacheEntityReference{TKey, TValue}"/> object the underlying cached item will not be evicted from the cache.
14+
/// </summary>
915
public sealed class DefaultEvictionBehavior : IEvictionBehavior
1016
{
1117
private readonly CancellationTokenSource _cts;

AsyncMemoryCache/EvictionBehaviors/EvictionBehavior.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,26 @@ namespace AsyncMemoryCache.EvictionBehaviors;
55

66
public static class EvictionBehavior
77
{
8+
/// <inheritdoc cref="DefaultEvictionBehavior"/>
89
#if NET8_0_OR_GREATER
910
public static readonly IEvictionBehavior Default = new DefaultEvictionBehavior(TimeProvider.System);
1011
#else
1112
public static readonly IEvictionBehavior Default = new DefaultEvictionBehavior();
1213
#endif
14+
/// <inheritdoc cref="NoOpEvictionBehavior"/>
1315
public static readonly IEvictionBehavior Disabled = new NoOpEvictionBehavior();
1416
}
1517

1618
public interface IEvictionBehavior : IAsyncDisposable
1719
{
20+
/// <summary>
21+
/// The method which starts the <see cref="IEvictionBehavior"/>.
22+
/// Called automatically by <see cref="AsyncMemoryCache{TKey, TValue}"/>.
23+
/// </summary>
24+
/// <typeparam name="TKey">The type of the key of the <see cref="CacheEntity{TKey, TValue}"/></typeparam>
25+
/// <typeparam name="TValue">The type of the value of the <see cref="CacheEntity{TKey, TValue}"/></typeparam>
26+
/// <param name="configuration">The configuration object used in <see cref="AsyncMemoryCache{TKey, TValue}"/> which contains the backing store that holds all of the cached objects</param>
27+
/// <param name="logger">The logger object</param>
1828
void Start<TKey, TValue>(IAsyncMemoryCacheConfiguration<TKey, TValue> configuration, ILogger<AsyncMemoryCache<TKey, TValue>> logger)
1929
where TKey : notnull
2030
where TValue : IAsyncDisposable;

AsyncMemoryCache/EvictionBehaviors/NoOpEvictionBehavior.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
namespace AsyncMemoryCache.EvictionBehaviors;
77

8+
/// <summary>
9+
/// A no-op implementation of <see cref="IEvictionBehavior"/>.
10+
/// This class has no behavior. Use this to disable eviction functionality.
11+
/// </summary>
812
#if NET8_0_OR_GREATER
913
[ExcludeFromCodeCoverage(Justification = "Nothing to test")]
1014
#endif
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
namespace AsyncMemoryCache.ExpirationStrategy;
22

3+
/// <summary>
4+
/// An interface used to provide custom implementations and rules surrounding the expiration of a <see cref="CacheEntity{TKey, TValue}"/> object.
5+
/// </summary>
36
public interface IExpirationStrategy
47
{
8+
/// <summary>
9+
/// A method that evaluates whether or not a <see cref="CacheEntity{TKey, TValue}"/> is expired.
10+
/// </summary>
11+
/// <returns>A <see cref="bool"/> that indicates whether or not the <see cref="CacheEntity{TKey, TValue}"/> being interrogated is expired.</returns>
512
bool IsExpired();
13+
14+
/// <summary>
15+
/// A method that is called by the cache every time the <see cref="CacheEntity{TKey, TValue}"/> this expiration strategy belongs to is used.
16+
/// </summary>
617
void CacheEntityAccessed();
718
}

AsyncMemoryCache/Extensions/CacheEntityReferenceExtensions.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ namespace AsyncMemoryCache.Extensions;
55

66
public static class CacheEntityReferenceExtensions
77
{
8+
/// <summary>
9+
/// Helper method that sets the <see cref="CacheEntity{TKey, TValue}.ExpirationStrategy"/> to a new instance of <see cref="AbsoluteExpirationStrategy"/>.<br/>
10+
/// This strategy takes an absolute date into account when evaluating whether or not it is expired.<br/>
11+
/// Useful when more control over the lifetime of a <see cref="CacheEntity{TKey, TValue}"/> is desirable or when there are downsides to having the object alive for an indeterminate amount of time.<para/>
12+
/// This is a direct proxy to <see cref="CacheEntity{TKey, TValue}.WithAbsoluteExpiration(DateTimeOffset)"/>
13+
/// </summary>
14+
/// <param name="cacheEntityReference">The <see cref="CacheEntityReference{TKey, TValue}"/></param>
15+
/// <param name="expiryDate">The configurable exact date used when evaluating if the object should be expired.</param>
16+
/// <returns><see langword="this"/> to enable chained calls</returns>
817
public static CacheEntityReference<TKey, TValue> WithAbsoluteExpiration<TKey, TValue>(this CacheEntityReference<TKey, TValue> cacheEntityReference, DateTimeOffset expiryDate)
918
where TKey : notnull
1019
where TValue : IAsyncDisposable
@@ -13,6 +22,15 @@ public static CacheEntityReference<TKey, TValue> WithAbsoluteExpiration<TKey, TV
1322
return cacheEntityReference;
1423
}
1524

25+
/// <summary>
26+
/// Helper method that sets the <see cref="CacheEntity{TKey, TValue}.ExpirationStrategy"/> to a new instance of <see cref="SlidingExpirationStrategy"/>.<br/>
27+
/// This strategy takes the last use of a <see cref="CacheEntity{TKey, TValue}"/> into account when evaluating whether or not it is expired.<br/>
28+
/// Useful when a cached object is actively used and there is no apparent downside in keeping the cached object alive for an indeterminate amount of time.<para/>
29+
/// This is a direct proxy to <see cref="CacheEntity{TKey, TValue}.WithSlidingExpiration(TimeSpan)"/>
30+
/// </summary>
31+
/// <param name="cacheEntityReference">The <see cref="CacheEntityReference{TKey, TValue}"/></param>
32+
/// <param name="slidingExpirationWindow">The configurable window used when evaluating if the object should be expired.</param>
33+
/// <returns><see langword="this"/> to enable chained calls</returns>
1634
public static CacheEntityReference<TKey, TValue> WithSlidingExpiration<TKey, TValue>(this CacheEntityReference<TKey, TValue> cacheEntityReference, TimeSpan slidingExpirationWindow)
1735
where TKey : notnull
1836
where TValue : IAsyncDisposable
@@ -21,6 +39,13 @@ public static CacheEntityReference<TKey, TValue> WithSlidingExpiration<TKey, TVa
2139
return cacheEntityReference;
2240
}
2341

42+
/// <summary>
43+
/// Helper method that sets the <see cref="CacheEntity{TKey, TValue}.ExpirationStrategy"/> to the provided instance of a custom implementation of <see cref="IExpirationStrategy"/>.<br/>
44+
/// This is a direct proxy to <see cref="CacheEntity{TKey, TValue}.WithExpirationStrategy(IExpirationStrategy)"/>
45+
/// </summary>
46+
/// <param name="cacheEntityReference">The <see cref="CacheEntityReference{TKey, TValue}"/></param>
47+
/// <param name="expirationStrategy">The custom implementation instance of <see cref="IExpirationStrategy"/></param>
48+
/// <returns><see langword="this"/> to enable chained calls</returns>
2449
public static CacheEntityReference<TKey, TValue> WithExpirationStrategy<TKey, TValue>(this CacheEntityReference<TKey, TValue> cacheEntityReference, IExpirationStrategy expirationStrategy)
2550
where TKey : notnull
2651
where TValue : IAsyncDisposable
@@ -29,6 +54,13 @@ public static CacheEntityReference<TKey, TValue> WithExpirationStrategy<TKey, TV
2954
return cacheEntityReference;
3055
}
3156

57+
/// <summary>
58+
/// Helper method that configures the <see cref="CacheEntity{TKey, TValue}.ExpirationCallback"/><br/>
59+
/// This is a direct proxy to <see cref="CacheEntity{TKey, TValue}.WithExpirationCallback(Action{TKey, TValue})"/>
60+
/// </summary>
61+
/// <param name="cacheEntityReference">The <see cref="CacheEntityReference{TKey, TValue}"/></param>
62+
/// <param name="expirationCallback">The callback which will be invoked when this instance of <see cref="CacheEntity{TKey, TValue}"/> expires.</param>
63+
/// <returns><see langword="this"/> to enable chained calls</returns>
3264
public static CacheEntityReference<TKey, TValue> WithExpirationCallback<TKey, TValue>(this CacheEntityReference<TKey, TValue> cacheEntityReference, Action<TKey, TValue> expirationCallback)
3365
where TKey : notnull
3466
where TValue : IAsyncDisposable

0 commit comments

Comments
 (0)