@@ -12,19 +12,19 @@ public class ValueSubsystem : CliSubsystem
12
12
// @mhutch: Is the TryGet on the sparse dictionaries how we should handle a case where the annotations will be sparse to support lazy? If so, should we have another method on
13
13
// the annotation wrapper, or an alternative struct when there a TryGet makes sense? This API needs review, maybe next Tuesday.
14
14
private PipelineContext ? pipelineContext = null ;
15
+ private Dictionary < CliSymbol , object ? > cachedValues = new ( ) ;
15
16
16
17
public ValueSubsystem ( IAnnotationProvider ? annotationProvider = null )
17
18
: base ( ValueAnnotations . Prefix , SubsystemKind . Version , annotationProvider )
18
19
{ }
19
20
20
- //TODO: ExplicitDefault might have a valid null value, and thus try pattern. DefaultCalculation is only null when not present. Consider whether to use the same pattern (try on DefaultCalculation, even though it is not needed)
21
- internal void SetExplicitDefault ( CliSymbol symbol , object ? defaultValue )
22
- => SetAnnotation ( symbol , ValueAnnotations . ExplicitDefault , defaultValue ) ;
23
- internal object ? GetExplicitDefault ( CliSymbol symbol )
24
- => TryGetAnnotation ( symbol , ValueAnnotations . ExplicitDefault , out var defaultValue )
21
+ internal void SetDefaultValue ( CliSymbol symbol , object ? defaultValue )
22
+ => SetAnnotation ( symbol , ValueAnnotations . DefaultValue , defaultValue ) ;
23
+ internal object ? GetDefaultValue ( CliSymbol symbol )
24
+ => TryGetAnnotation ( symbol , ValueAnnotations . DefaultValue , out var defaultValue )
25
25
? defaultValue
26
26
: "" ;
27
- internal bool TryGetExplicitDefault < T > ( CliSymbol symbol , out T ? defaultValue )
27
+ internal bool TryGetDefaultValue < T > ( CliSymbol symbol , out T ? defaultValue )
28
28
{
29
29
if ( TryGetAnnotation ( symbol , ValueAnnotations . Value , out var objectValue ) )
30
30
{
@@ -34,17 +34,17 @@ internal bool TryGetExplicitDefault<T>(CliSymbol symbol, out T? defaultValue)
34
34
defaultValue = default ;
35
35
return false ;
36
36
}
37
- public AnnotationAccessor < object ? > ExplicitDefault
38
- => new ( this , ValueAnnotations . ExplicitDefault ) ;
37
+ public AnnotationAccessor < object ? > DefaultValue
38
+ => new ( this , ValueAnnotations . DefaultValue ) ;
39
39
40
- internal void SetDefaultCalculation ( CliSymbol symbol , Func < object ? > factory )
41
- => SetAnnotation ( symbol , ValueAnnotations . DefaultCalculation , factory ) ;
42
- internal Func < object ? > ? GetDefaultCalculation ( CliSymbol symbol )
43
- => TryGetAnnotation < Func < object ? > ? > ( symbol , ValueAnnotations . DefaultCalculation , out var value )
40
+ internal void SetDefaultValueCalculation ( CliSymbol symbol , Func < object ? > factory )
41
+ => SetAnnotation ( symbol , ValueAnnotations . DefaultValueCalculation , factory ) ;
42
+ internal Func < object ? > ? GetDefaultValueCalculation ( CliSymbol symbol )
43
+ => TryGetAnnotation < Func < object ? > ? > ( symbol , ValueAnnotations . DefaultValueCalculation , out var value )
44
44
? value
45
45
: null ;
46
- public AnnotationAccessor < Func < object ? > ? > DefaultCalculation
47
- => new ( this , ValueAnnotations . DefaultCalculation ) ;
46
+ public AnnotationAccessor < Func < object ? > ? > DefaultValueCalculation
47
+ => new ( this , ValueAnnotations . DefaultValueCalculation ) ;
48
48
49
49
protected internal override bool GetIsActivated ( ParseResult ? parseResult )
50
50
=> true ;
@@ -55,82 +55,48 @@ protected internal override CliExit Execute(PipelineContext pipelineContext)
55
55
return CliExit . NotRun ( pipelineContext . ParseResult ) ;
56
56
}
57
57
58
- // TODO: Consider using a simple dictionary instead of the annotation (@mhutch) because with is not useful here
58
+
59
+ // TODO: Do it! Consider using a simple dictionary instead of the annotation (@mhutch) because with is not useful here
59
60
private void SetValue < T > ( CliSymbol symbol , object ? value )
60
- => SetAnnotation ( symbol , ValueAnnotations . Value , value ) ;
61
- // TODO: Consider a way to disallow CliCommand here, as it creates a pit of failure.
61
+ => cachedValues . Add ( symbol , value ) ;
62
62
private bool TryGetValue < T > ( CliSymbol symbol , out T ? value )
63
63
{
64
- if ( TryGetAnnotation ( symbol , ValueAnnotations . Value , out var objectValue ) )
64
+ if ( cachedValues . TryGetValue ( symbol , out var objectValue ) )
65
65
{
66
- value = ( T ) objectValue ;
66
+ value = objectValue is null
67
+ ? default
68
+ : ( T ) objectValue ;
67
69
return true ;
68
70
}
69
71
value = default ;
70
72
return false ;
71
73
}
72
- // TODO: Is fluent style meaningful for Value?
73
- //public AnnotationAccessor<object?> Value
74
- // => new(this, ValueAnnotations.Value);
75
74
76
75
public T ? GetValue < T > ( CliOption option )
77
76
=> GetValueInternal < T > ( option ) ;
78
77
public T ? GetValue < T > ( CliArgument argument )
79
78
=> GetValueInternal < T > ( argument ) ;
80
79
81
- // TODO: @mhutch: I find this more readable than the if conditional version below. There will be at least two more blocks. Look good?
82
- private T ? GetValueInternal < T > ( CliSymbol symbol )
80
+ private T ? GetValueInternal < T > ( CliSymbol ? symbol )
83
81
=> symbol switch
84
82
{
85
- { } when TryGetValue < T > ( symbol , out var value )
83
+ not null when TryGetValue < T > ( symbol , out var value )
86
84
=> value , // It has already been retrieved at least once
87
- { } when pipelineContext ? . ParseResult ? . GetValueResult ( symbol ) is ValueResult valueResult
85
+ CliArgument argument when pipelineContext ? . ParseResult ? . GetValueResult ( argument ) is ValueResult valueResult // GetValue would always return a value
86
+ => UseValue ( symbol , valueResult . GetValue < T > ( ) ) , // Value was supplied during parsing,
87
+ CliOption option when pipelineContext ? . ParseResult ? . GetValueResult ( option ) is ValueResult valueResult // GetValue would always return a value
88
88
=> UseValue ( symbol , valueResult . GetValue < T > ( ) ) , // Value was supplied during parsing
89
89
// Value was not supplied during parsing, determine default now
90
- { } when GetDefaultCalculation ( symbol ) is { } defaultValueCalculation
90
+ not null when DefaultValueCalculation . TryGet ( symbol , out var defaultValueCalculation )
91
91
=> UseValue ( symbol , CalculatedDefault < T > ( symbol , defaultValueCalculation ) ) ,
92
- { } when TryGetExplicitDefault < T > ( symbol , out var explicitValue )
92
+ not null when TryGetDefaultValue < T > ( symbol , out var explicitValue )
93
93
=> UseValue ( symbol , explicitValue ) ,
94
+ //not null when GetDefaultFromEnvironmentVariable<T>(symbol, out var envName)
95
+ // => UseValue(symbol, GetEnvByName(envName)),
94
96
null => throw new ArgumentNullException ( nameof ( symbol ) ) ,
95
97
_ => UseValue ( symbol , default ( T ) )
96
98
} ;
97
99
98
- //// The following is temporarily included for showing why the above weird code is cleaner
99
- //public T? GetValue2<T>(CliSymbol symbol)
100
- //{
101
- // if (TryGetValue<T>(symbol, out var value))
102
- // {
103
- // // It has already been retrieved at least once
104
- // return value;
105
- // }
106
- // if (pipelineContext?.ParseResult?.GetValueResult(symbol) is ValueResult valueResult)
107
- // {
108
- // // Value was supplied during parsing
109
- // return UseValue(symbol, valueResult.GetValue<T>());
110
- // }
111
- // // Value was not supplied during parsing, determine default now
112
- // if (GetDefaultCalculation(symbol) is { } defaultValueCalculation)
113
- // {
114
- // return UseValue(symbol, CalculatedDefault(symbol, defaultValueCalculation));
115
- // }
116
- // if (TryGetExplicitDefault<T>(symbol, out var explicitValue))
117
- // {
118
- // return UseValue(symbol, value);
119
- // }
120
- // value = default;
121
- // SetValue<T>(symbol, value);
122
- // return value;
123
-
124
- // static T? CalculatedDefault(CliSymbol symbol, Func<object?> defaultValueCalculation)
125
- // {
126
- // var objectValue = defaultValueCalculation();
127
- // var value = objectValue is null
128
- // ? default
129
- // : (T)objectValue;
130
- // return value;
131
- // }
132
- //}
133
-
134
100
private static T ? CalculatedDefault < T > ( CliSymbol symbol , Func < object ? > defaultValueCalculation )
135
101
{
136
102
var objectValue = defaultValueCalculation ( ) ;
0 commit comments