|
10 | 10 | /// </remarks> |
11 | 11 | internal abstract class OutcomeResilienceStrategy<T> : ResilienceStrategy |
12 | 12 | { |
13 | | - private readonly bool _isGeneric; |
14 | | - |
15 | | - protected OutcomeResilienceStrategy(bool isGeneric) |
16 | | - { |
17 | | - if (!isGeneric && typeof(T) != typeof(object)) |
18 | | - { |
19 | | - throw new NotSupportedException("For non-generic strategies the generic parameter should be of type 'object'."); |
20 | | - } |
21 | | - |
22 | | - _isGeneric = isGeneric; |
23 | | - } |
24 | | - |
25 | 13 | protected internal sealed override ValueTask<Outcome<TResult>> ExecuteCore<TResult, TState>( |
26 | 14 | Func<ResilienceContext, TState, ValueTask<Outcome<TResult>>> callback, |
27 | 15 | ResilienceContext context, |
28 | 16 | TState state) |
29 | 17 | { |
30 | | - if (_isGeneric) |
| 18 | + // Check if we can cast directly, thus saving some cycles and improving the performance |
| 19 | + if (context.ResultType == typeof(T)) |
31 | 20 | { |
32 | | - if (typeof(TResult) != typeof(T)) |
33 | | - { |
34 | | - return callback(context, state); |
35 | | - } |
36 | | - |
37 | 21 | // cast is safe here, because TResult and T are the same type |
38 | 22 | var callbackCasted = (Func<ResilienceContext, TState, ValueTask<Outcome<T>>>)(object)callback; |
39 | | - var valueTask = ExecuteCallbackAsync(callbackCasted, context, state); |
| 23 | + var valueTask = ExecuteCore(callbackCasted, context, state); |
40 | 24 |
|
41 | | - return ConvertValueTask<TResult>(valueTask, context); |
| 25 | + return TaskHelper.ConvertValueTask<T, TResult>(valueTask, context); |
42 | 26 | } |
43 | 27 | else |
44 | 28 | { |
45 | | - var valueTask = ExecuteCallbackAsync( |
| 29 | + var valueTask = ExecuteCore( |
46 | 30 | static async (context, state) => |
47 | 31 | { |
48 | 32 | var outcome = await state.callback(context, state.state).ConfigureAwait(context.ContinueOnCapturedContext); |
49 | | - |
50 | | - // cast the outcome to "object" based on (T) |
51 | 33 | return outcome.AsOutcome<T>(); |
52 | 34 | }, |
53 | 35 | context, |
54 | 36 | (callback, state)); |
55 | 37 |
|
56 | | - return ConvertValueTask<TResult>(valueTask, context); |
| 38 | + return TaskHelper.ConvertValueTask<T, TResult>(valueTask, context); |
57 | 39 | } |
58 | 40 | } |
59 | 41 |
|
60 | | - protected abstract ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>( |
| 42 | + protected abstract ValueTask<Outcome<T>> ExecuteCore<TState>( |
61 | 43 | Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, |
62 | 44 | ResilienceContext context, |
63 | 45 | TState state); |
64 | | - |
65 | | - private static ValueTask<Outcome<TResult>> ConvertValueTask<TResult>(ValueTask<Outcome<T>> valueTask, ResilienceContext resilienceContext) |
66 | | - { |
67 | | - if (valueTask.IsCompletedSuccessfully) |
68 | | - { |
69 | | - return new ValueTask<Outcome<TResult>>(valueTask.Result.AsOutcome<TResult>()); |
70 | | - } |
71 | | - |
72 | | - return ConvertValueTaskAsync(valueTask, resilienceContext); |
73 | | - |
74 | | - static async ValueTask<Outcome<TResult>> ConvertValueTaskAsync(ValueTask<Outcome<T>> valueTask, ResilienceContext resilienceContext) |
75 | | - { |
76 | | - var outcome = await valueTask.ConfigureAwait(resilienceContext.ContinueOnCapturedContext); |
77 | | - return outcome.AsOutcome<TResult>(); |
78 | | - } |
79 | | - } |
80 | 46 | } |
0 commit comments