@@ -121,6 +121,52 @@ public ArgumentAttribute(char shortName, string longName, string helpText = null
121
121
public char ShortName { get ; set ; }
122
122
}
123
123
124
+ /// <summary>
125
+ /// Encapsulates argument names and help text.
126
+ /// </summary>
127
+ public class ArgumentInfo
128
+ {
129
+ /// <summary>
130
+ /// Initializes a new instance of the <see cref="ArgumentInfo"/> class.
131
+ /// </summary>
132
+ /// <param name="shortName">The short name of the argument.</param>
133
+ /// <param name="longName">The long name of the argument.</param>
134
+ /// <param name="helpText">The help text for the argument.</param>
135
+ /// <param name="property">The property with which the argument is associated.</param>
136
+ public ArgumentInfo ( char shortName , string longName , string helpText , PropertyInfo property )
137
+ {
138
+ ShortName = shortName ;
139
+ LongName = longName ;
140
+ HelpText = helpText ;
141
+ Property = property ;
142
+ }
143
+
144
+ /// <summary>
145
+ /// Gets the help text for the argument.
146
+ /// </summary>
147
+ public string HelpText { get ; }
148
+
149
+ /// <summary>
150
+ /// Gets a value indicating whether the argument backing Type is a collection.
151
+ /// </summary>
152
+ public bool IsCollection => Property . PropertyType . IsArray || ( Property . PropertyType . IsGenericType && Property . PropertyType . GetGenericTypeDefinition ( ) == typeof ( List < > ) ) ;
153
+
154
+ /// <summary>
155
+ /// Gets the long name of the argument.
156
+ /// </summary>
157
+ public string LongName { get ; }
158
+
159
+ /// <summary>
160
+ /// Gets the property with which the argument is associated.
161
+ /// </summary>
162
+ public PropertyInfo Property { get ; }
163
+
164
+ /// <summary>
165
+ /// Gets the short name of the argument.
166
+ /// </summary>
167
+ public char ShortName { get ; }
168
+ }
169
+
124
170
/// <summary>
125
171
/// Provides static methods used to retrieve the command line arguments and operands with which the application was
126
172
/// started, as well as a Type to contain them.
@@ -162,21 +208,25 @@ private Arguments(string commandLineString, List<KeyValuePair<string, string>> a
162
208
}
163
209
164
210
/// <summary>
165
- /// Gets the target Type, if applicable.
211
+ /// Gets a dictionary containing the arguments and values specified in the command line arguments with which the
212
+ /// application was started.
166
213
/// </summary>
167
- public Type TargetType { get ; }
214
+ /// <remarks>
215
+ /// This dictionary contains argument key/value pairs compiled from the <see cref="ArgumentList"/> and checked against
216
+ /// the <see cref="TargetType"/> to combine duplicated pairs into lists where the backing property is a collection, and
217
+ /// to overwrite where the backing property is not a collection.
218
+ /// </remarks>
219
+ public Dictionary < string , object > ArgumentDictionary { get ; }
168
220
169
221
/// <summary>
170
222
/// Gets the list of arguments specified in the command line arguments with which the application was started.
171
223
/// </summary>
224
+ /// <remarks>
225
+ /// This list contains each argument key/value pair as supplied in the original string, preserving the original order
226
+ /// and any duplicated pairs.
227
+ /// </remarks>
172
228
public List < KeyValuePair < string , string > > ArgumentList { get ; }
173
229
174
- /// <summary>
175
- /// Gets a dictionary containing the arguments and values specified in the command line arguments with which the
176
- /// application was started.
177
- /// </summary>
178
- public Dictionary < string , object > ArgumentDictionary { get ; }
179
-
180
230
/// <summary>
181
231
/// Gets the command line string from which the arguments were parsed.
182
232
/// </summary>
@@ -187,6 +237,11 @@ private Arguments(string commandLineString, List<KeyValuePair<string, string>> a
187
237
/// </summary>
188
238
public List < string > OperandList { get ; private set ; }
189
239
240
+ /// <summary>
241
+ /// Gets the target Type, if applicable.
242
+ /// </summary>
243
+ public Type TargetType { get ; }
244
+
190
245
/// <summary>
191
246
/// Gets the argument value corresponding to the specified <paramref name="index"/>.
192
247
/// </summary>
@@ -201,7 +256,8 @@ public object this[int index]
201
256
}
202
257
203
258
/// <summary>
204
- /// Gets the argument value corresponding to the specified <paramref name="key"/> from the <see cref="ArgumentDictionary"/> property.
259
+ /// Gets the argument value corresponding to the specified <paramref name="key"/> from the
260
+ /// <see cref="ArgumentDictionary"/> property.
205
261
/// </summary>
206
262
/// <param name="key">The key for which the value is to be retrieved.</param>
207
263
/// <returns>The argument value corresponding to the specified key.</returns>
@@ -213,43 +269,6 @@ public object this[string key]
213
269
}
214
270
}
215
271
216
- private static Dictionary < string , object > GetArgumentDictionary ( List < KeyValuePair < string , string > > argumentList , Type targetType = null )
217
- {
218
- var dict = new ConcurrentDictionary < string , object > ( ) ;
219
- var argumentInfo = targetType == null ? new List < ArgumentInfo > ( ) : GetArgumentInfo ( targetType ) ;
220
-
221
- foreach ( var arg in argumentList )
222
- {
223
- var info = argumentInfo . Where ( i => i . ShortName . ToString ( ) == arg . Key || i . LongName == arg . Key ) . SingleOrDefault ( ) ;
224
-
225
- if ( info != default ( ArgumentInfo ) )
226
- {
227
- bool added = false ;
228
-
229
- foreach ( var k in new [ ] { info . ShortName . ToString ( ) , info . LongName } )
230
- {
231
- if ( dict . ContainsKey ( k ) )
232
- {
233
- dict . AddOrUpdate ( k , arg . Value , ( key , existingValue ) => info . IsCollection ? ( ( List < object > ) existingValue ) . Concat ( new [ ] { arg . Value } ) . ToList ( ) : ( object ) arg . Value ) ;
234
- added = true ;
235
- break ;
236
- }
237
- }
238
-
239
- if ( ! added )
240
- {
241
- dict . TryAdd ( arg . Key , info . IsCollection ? new List < object > ( new [ ] { arg . Value } ) : ( object ) arg . Value ) ;
242
- }
243
- }
244
- else
245
- {
246
- dict . AddOrUpdate ( arg . Key , arg . Value , ( key , existingValue ) => arg . Value ) ;
247
- }
248
- }
249
-
250
- return dict . ToDictionary ( a => a . Key , a => a . Value ) ;
251
- }
252
-
253
272
/// <summary>
254
273
/// Retrieves a collection of <see cref="ArgumentInfo"/> gathered from properties in the target <paramref name="type"/>
255
274
/// marked with the <see cref="ArgumentAttribute"/><see cref="Attribute"/> along with the short and long names and help text.
@@ -268,13 +287,11 @@ private static Dictionary<string, object> GetArgumentDictionary(List<KeyValuePai
268
287
269
288
if ( attribute != default ( CustomAttributeData ) )
270
289
{
271
- retVal . Add ( new ArgumentInfo ( )
272
- {
273
- ShortName = ( char ) attribute . ConstructorArguments [ 0 ] . Value ,
274
- LongName = ( string ) attribute . ConstructorArguments [ 1 ] . Value ,
275
- HelpText = ( string ) attribute . ConstructorArguments [ 2 ] . Value ,
276
- Type = property . PropertyType ,
277
- } ) ;
290
+ retVal . Add ( new ArgumentInfo (
291
+ shortName : ( char ) attribute . ConstructorArguments [ 0 ] . Value ,
292
+ longName : ( string ) attribute . ConstructorArguments [ 1 ] . Value ,
293
+ helpText : ( string ) attribute . ConstructorArguments [ 2 ] . Value ,
294
+ property : property ) ) ;
278
295
}
279
296
}
280
297
@@ -413,16 +430,7 @@ public static void Populate(Type type, Arguments arguments, bool clearExistingVa
413
430
}
414
431
else if ( propertyType . IsArray || ( propertyType . IsGenericType && propertyType . GetGenericTypeDefinition ( ) == typeof ( List < > ) ) )
415
432
{
416
- // if the property is an array or list, convert the value to an array or list of the matching type. start
417
- // by converting atomic values to a list containing a single value, just to simplify processing.
418
- if ( valueIsList )
419
- {
420
- convertedValue = value ;
421
- }
422
- else
423
- {
424
- convertedValue = new List < object > ( new object [ ] { value } ) ;
425
- }
433
+ convertedValue = value ;
426
434
427
435
// next, create a list with the same type as the target property
428
436
Type valueType ;
@@ -526,6 +534,43 @@ private static void ClearProperties(Dictionary<string, PropertyInfo> properties)
526
534
}
527
535
}
528
536
537
+ private static Dictionary < string , object > GetArgumentDictionary ( List < KeyValuePair < string , string > > argumentList , Type targetType = null )
538
+ {
539
+ var dict = new ConcurrentDictionary < string , object > ( ) ;
540
+ var argumentInfo = targetType == null ? new List < ArgumentInfo > ( ) : GetArgumentInfo ( targetType ) ;
541
+
542
+ foreach ( var arg in argumentList )
543
+ {
544
+ var info = argumentInfo . Where ( i => i . ShortName . ToString ( ) == arg . Key || i . LongName == arg . Key ) . SingleOrDefault ( ) ;
545
+
546
+ if ( info != default ( ArgumentInfo ) )
547
+ {
548
+ bool added = false ;
549
+
550
+ foreach ( var k in new [ ] { info . ShortName . ToString ( ) , info . LongName } )
551
+ {
552
+ if ( dict . ContainsKey ( k ) )
553
+ {
554
+ dict . AddOrUpdate ( k , arg . Value , ( key , existingValue ) => info . IsCollection ? ( ( List < object > ) existingValue ) . Concat ( new [ ] { arg . Value } ) . ToList ( ) : ( object ) arg . Value ) ;
555
+ added = true ;
556
+ break ;
557
+ }
558
+ }
559
+
560
+ if ( ! added )
561
+ {
562
+ dict . TryAdd ( arg . Key , info . IsCollection ? new List < object > ( new [ ] { arg . Value } ) : ( object ) arg . Value ) ;
563
+ }
564
+ }
565
+ else
566
+ {
567
+ dict . AddOrUpdate ( arg . Key , arg . Value , ( key , existingValue ) => arg . Value ) ;
568
+ }
569
+ }
570
+
571
+ return dict . ToDictionary ( a => a . Key , a => a . Value ) ;
572
+ }
573
+
529
574
private static List < KeyValuePair < string , string > > GetArgumentList ( string commandLineString )
530
575
{
531
576
var argumentList = new List < KeyValuePair < string , string > > ( ) ;
@@ -640,37 +685,6 @@ private static PropertyInfo GetOperandsProperty(Type type)
640
685
}
641
686
}
642
687
643
- /// <summary>
644
- /// Encapsulates argument names and help text.
645
- /// </summary>
646
- public class ArgumentInfo
647
- {
648
- /// <summary>
649
- /// Gets or sets the help text for the argument.
650
- /// </summary>
651
- public string HelpText { get ; set ; }
652
-
653
- /// <summary>
654
- /// Gets or sets the long name of the argument.
655
- /// </summary>
656
- public string LongName { get ; set ; }
657
-
658
- /// <summary>
659
- /// Gets or sets the short name of the argument.
660
- /// </summary>
661
- public char ShortName { get ; set ; }
662
-
663
- /// <summary>
664
- /// Gets or sets the backing Type of the argument.
665
- /// </summary>
666
- public Type Type { get ; set ; }
667
-
668
- /// <summary>
669
- /// Gets a value indicating whether the argument backing Type is a collection.
670
- /// </summary>
671
- public bool IsCollection => Type . IsArray || ( Type . IsGenericType && Type . GetGenericTypeDefinition ( ) == typeof ( List < > ) ) ;
672
- }
673
-
674
688
/// <summary>
675
689
/// Indicates that the property is to be used as the target for automatic population of command line operands when invoking
676
690
/// the <see cref="Arguments.Populate(string, bool, string)"/> method.
@@ -679,4 +693,4 @@ public class ArgumentInfo
679
693
public class OperandsAttribute : Attribute
680
694
{
681
695
}
682
- }
696
+ }
0 commit comments