@@ -20,25 +20,30 @@ public DistributedCache(IOptions<TypedDistributedCacheOptions> options, ICacheSe
20
20
_ = options ;
21
21
}
22
22
23
- public ValueTask < T > GetAsync ( string key , Func < ValueTask < T > > callback , DistributedCacheEntryOptions ? options = null , CancellationToken cancellationToken = default )
23
+ // for the simple usage scenario (no TState), pack the original callback as the "state", and use a wrapper function that just unrolls and invokes from the state
24
+ static readonly Func < Func < CancellationToken , ValueTask < T > > , CancellationToken , ValueTask < T > > _wrapped = static ( callback , ct ) => callback ( ct ) ;
25
+ public ValueTask < T > GetAsync ( string key , Func < CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options = null , CancellationToken cancellationToken = default )
26
+ => GetAsync ( key , callback , _wrapped , options , cancellationToken ) ;
27
+
28
+ public ValueTask < T > GetAsync < TState > ( string key , TState state , Func < TState , CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options = null , CancellationToken cancellationToken = default )
24
29
{
25
30
ArgumentException . ThrowIfNullOrWhiteSpace ( key ) ;
26
31
ArgumentNullException . ThrowIfNull ( callback ) ;
27
32
28
33
return _bufferBackend is not null
29
- ? GetBufferedBackendAsync ( key , callback , options , cancellationToken )
30
- : GetLegacyBackendAsync ( key , callback , options , cancellationToken ) ;
34
+ ? GetBufferedBackendAsync ( key , state , callback , options , cancellationToken )
35
+ : GetLegacyBackendAsync ( key , state , callback , options , cancellationToken ) ;
31
36
32
37
}
33
38
34
- private ValueTask < T > GetBufferedBackendAsync ( string key , Func < ValueTask < T > > callback , DistributedCacheEntryOptions ? options , CancellationToken cancellationToken )
39
+ private ValueTask < T > GetBufferedBackendAsync < TState > ( string key , TState state , Func < TState , CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options , CancellationToken cancellationToken )
35
40
{
36
41
var buffer = new RecyclableArrayBufferWriter < byte > ( ) ;
37
42
var pendingGet = _bufferBackend ! . TryGetAsync ( key , buffer , cancellationToken ) ;
38
43
39
44
if ( ! pendingGet . IsCompletedSuccessfully )
40
45
{
41
- return AwaitedBackend ( this , key , callback , options , cancellationToken , buffer , pendingGet ) ;
46
+ return AwaitedBackend ( this , key , state , callback , options , cancellationToken , buffer , pendingGet ) ;
42
47
}
43
48
44
49
// fast path; backend available immediately
@@ -50,9 +55,9 @@ private ValueTask<T> GetBufferedBackendAsync(string key, Func<ValueTask<T>> call
50
55
}
51
56
52
57
// fall back to main code-path, but without the pending bytes (we've already checked those)
53
- return AwaitedBackend ( this , key , callback , options , cancellationToken , buffer , default ) ;
58
+ return AwaitedBackend ( this , key , state , callback , options , cancellationToken , buffer , default ) ;
54
59
55
- static async ValueTask < T > AwaitedBackend ( DistributedCache < T > @this , string key , Func < ValueTask < T > > callback , DistributedCacheEntryOptions ? options ,
60
+ static async ValueTask < T > AwaitedBackend ( DistributedCache < T > @this , string key , TState state , Func < TState , CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options ,
56
61
CancellationToken cancellationToken , RecyclableArrayBufferWriter < byte > buffer , ValueTask < bool > pendingGet )
57
62
{
58
63
using ( buffer )
@@ -62,7 +67,7 @@ static async ValueTask<T> AwaitedBackend(DistributedCache<T> @this, string key,
62
67
return @this . _serializer . Deserialize ( new ( buffer . GetCommittedMemory ( ) ) ) ;
63
68
}
64
69
65
- var value = await callback ( ) ;
70
+ var value = await callback ( state , cancellationToken ) ;
66
71
if ( value is null )
67
72
{
68
73
await @this . _backend . RemoveAsync ( key , cancellationToken ) ;
@@ -79,12 +84,12 @@ static async ValueTask<T> AwaitedBackend(DistributedCache<T> @this, string key,
79
84
}
80
85
}
81
86
82
- private ValueTask < T > GetLegacyBackendAsync ( string key , Func < ValueTask < T > > callback , DistributedCacheEntryOptions ? options , CancellationToken cancellationToken )
87
+ private ValueTask < T > GetLegacyBackendAsync < TState > ( string key , TState state , Func < TState , CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options , CancellationToken cancellationToken )
83
88
{
84
89
var pendingBytes = _backend . GetAsync ( key , cancellationToken ) ;
85
90
if ( ! pendingBytes . IsCompletedSuccessfully )
86
91
{
87
- return AwaitedBackend ( this , key , callback , options , cancellationToken , pendingBytes ) ;
92
+ return AwaitedBackend ( this , key , state , callback , options , cancellationToken , pendingBytes ) ;
88
93
}
89
94
90
95
// fast path; backend available immediately
@@ -95,9 +100,9 @@ private ValueTask<T> GetLegacyBackendAsync(string key, Func<ValueTask<T>> callba
95
100
}
96
101
97
102
// fall back to main code-path, but without the pending bytes (we've already checked those)
98
- return AwaitedBackend ( this , key , callback , options , cancellationToken , null ) ;
103
+ return AwaitedBackend ( this , key , state , callback , options , cancellationToken , null ) ;
99
104
100
- static async ValueTask < T > AwaitedBackend ( DistributedCache < T > @this , string key , Func < ValueTask < T > > callback , DistributedCacheEntryOptions ? options ,
105
+ static async ValueTask < T > AwaitedBackend ( DistributedCache < T > @this , string key , TState state , Func < TState , CancellationToken , ValueTask < T > > callback , DistributedCacheEntryOptions ? options ,
101
106
CancellationToken cancellationToken , Task < byte [ ] ? > ? pendingBytes )
102
107
{
103
108
if ( pendingBytes is not null )
@@ -109,7 +114,7 @@ static async ValueTask<T> AwaitedBackend(DistributedCache<T> @this, string key,
109
114
}
110
115
}
111
116
112
- var value = await callback ( ) ;
117
+ var value = await callback ( state , cancellationToken ) ;
113
118
if ( value is null )
114
119
{
115
120
await @this . _backend . RemoveAsync ( key , cancellationToken ) ;
0 commit comments