@@ -167,6 +167,36 @@ public ArgumentInfo(char shortName, string longName, string helpText, PropertyIn
167167 public char ShortName { get ; }
168168 }
169169
170+ /// <summary>
171+ /// Parsing options.
172+ /// </summary>
173+ public class ArgumentParseOptions
174+ {
175+ /// <summary>
176+ /// Gets or sets the <see cref="Type"/> for which the command line string is to be parsed.
177+ /// </summary>
178+ /// <remarks>
179+ /// Supersedes combination options; arguments backed by properties of a collection type are combined, while those that aren't are not.
180+ /// </remarks>
181+ public Type TargetType { get ; set ; }
182+
183+ /// <summary>
184+ /// Gets or sets a value indicating whether duplicate argument values should be combined into a list.
185+ /// </summary>
186+ /// <remarks>
187+ /// Only applicable if <see cref="TargetType"/> is not specified.
188+ /// </remarks>
189+ public bool CombineAllMultiples { get ; set ; }
190+
191+ /// <summary>
192+ /// Gets or sets a value indicating whether duplicate argument values for arguments in the array should be combined into a list.
193+ /// </summary>
194+ /// <remarks>
195+ /// Only applicable if <see cref="TargetType"/> is not specified.
196+ /// </remarks>
197+ public string [ ] CombinableArguments { get ; set ; } = Array . Empty < string > ( ) ;
198+ }
199+
170200 /// <summary>
171201 /// Provides static methods used to retrieve the command line arguments and operands with which the application was
172202 /// started, as well as a Type to contain them.
@@ -310,19 +340,53 @@ public object this[string key]
310340 return retVal ;
311341 }
312342
343+ /// <summary>
344+ /// Returns a dictionary containing the values specified in the command line arguments with which the application was
345+ /// started, keyed by argument name.
346+ /// </summary>
347+ /// <param name="configure">An action to configure the provided <see cref="ArgumentParseOptions"/> instance.</param>
348+ /// <returns>
349+ /// The dictionary containing the arguments and values specified in the command line arguments with which the
350+ /// application was started.
351+ /// </returns>
352+ public static Arguments Parse ( Action < ArgumentParseOptions > configure = null )
353+ {
354+ return Parse ( null , configure ) ;
355+ }
356+
313357 /// <summary>
314358 /// Returns a dictionary containing the values specified in the command line arguments with which the application was
315359 /// started, keyed by argument name.
316360 /// </summary>
317361 /// <param name="commandLineString">The command line arguments with which the application was started.</param>
318- /// <param name="type">The <see cref="Type"/> for which the command line string is to be parsed.</param>
319- /// <param name="caller">Internal parameter used to identify the calling method.</param>
362+ /// <param name="configure">An action to configure the provided <see cref="ArgumentParseOptions"/> instance.</param>
363+ /// <returns>
364+ /// The dictionary containing the arguments and values specified in the command line arguments with which the
365+ /// application was started.
366+ /// </returns>
367+ public static Arguments Parse ( string commandLineString , Action < ArgumentParseOptions > configure = null )
368+ {
369+ configure = configure ?? new Action < ArgumentParseOptions > ( ( _ ) => { } ) ;
370+ var options = new ArgumentParseOptions ( ) ;
371+ configure ( options ) ;
372+
373+ return Parse ( commandLineString , options ) ;
374+ }
375+
376+ /// <summary>
377+ /// Returns a dictionary containing the values specified in the command line arguments with which the application was
378+ /// started, keyed by argument name.
379+ /// </summary>
380+ /// <param name="commandLineString">The command line arguments with which the application was started.</param>
381+ /// <param name="options">Parser options.</param>
320382 /// <returns>
321383 /// The dictionary containing the arguments and values specified in the command line arguments with which the
322384 /// application was started.
323385 /// </returns>
324- public static Arguments Parse ( string commandLineString = default ( string ) , Type type = null , [ CallerMemberName ] string caller = default ( string ) )
386+ public static Arguments Parse ( string commandLineString , ArgumentParseOptions options )
325387 {
388+ options = options ?? new ArgumentParseOptions ( ) ;
389+
326390 commandLineString = commandLineString == default ( string ) || string . IsNullOrEmpty ( commandLineString ) ? Environment . CommandLine : commandLineString ;
327391
328392 List < KeyValuePair < string , string > > argumentList ;
@@ -353,8 +417,8 @@ public object this[string key]
353417 operandList = GetOperandList ( commandLineString ) ;
354418 }
355419
356- var argumentDictionary = GetArgumentDictionary ( argumentList , type ) ;
357- return new Arguments ( commandLineString , argumentList , argumentDictionary , operandList , type ) ;
420+ var argumentDictionary = GetArgumentDictionary ( argumentList , options ) ;
421+ return new Arguments ( commandLineString , argumentList , argumentDictionary , operandList , options . TargetType ) ;
358422 }
359423
360424 /// <summary>
@@ -368,7 +432,7 @@ public object this[string key]
368432 public static void Populate ( string commandLineString = default ( string ) , bool clearExistingValues = true , [ CallerMemberName ] string caller = default ( string ) )
369433 {
370434 var type = ArgumentsExtensions . GetCallingType ( caller ) ;
371- Populate ( type , Parse ( commandLineString , type ) , clearExistingValues ) ;
435+ Populate ( type , Parse ( commandLineString , options => options . TargetType = type ) , clearExistingValues ) ;
372436 }
373437
374438 /// <summary>
@@ -383,7 +447,7 @@ public object this[string key]
383447 /// <param name="clearExistingValues">Whether to clear the properties before populating them. Defaults to true.</param>
384448 public static void Populate ( Type type , string commandLineString = default ( string ) , bool clearExistingValues = true )
385449 {
386- Populate ( type , Parse ( commandLineString , type ) , clearExistingValues ) ;
450+ Populate ( type , Parse ( commandLineString , options => options . TargetType = type ) , clearExistingValues ) ;
387451 }
388452
389453 /// <summary>
@@ -537,10 +601,10 @@ private static void ClearProperties(Dictionary<string, PropertyInfo> properties)
537601 }
538602 }
539603
540- private static Dictionary < string , object > GetArgumentDictionary ( List < KeyValuePair < string , string > > argumentList , Type targetType = null )
604+ private static Dictionary < string , object > GetArgumentDictionary ( List < KeyValuePair < string , string > > argumentList , ArgumentParseOptions options )
541605 {
542606 var dict = new ConcurrentDictionary < string , object > ( ) ;
543- var argumentInfo = targetType == null ? new List < ArgumentInfo > ( ) : GetArgumentInfo ( targetType ) ;
607+ var argumentInfo = options . TargetType == null ? new List < ArgumentInfo > ( ) : GetArgumentInfo ( options . TargetType ) ;
544608
545609 foreach ( var arg in argumentList )
546610 {
@@ -567,7 +631,22 @@ private static Dictionary<string, object> GetArgumentDictionary(List<KeyValuePai
567631 }
568632 else
569633 {
570- dict . AddOrUpdate ( arg . Key , arg . Value , ( key , existingValue ) => arg . Value ) ;
634+ if ( dict . ContainsKey ( arg . Key ) && ( options . CombineAllMultiples || options . CombinableArguments . Contains ( arg . Key ) ) )
635+ {
636+ dict . AddOrUpdate ( arg . Key , arg . Value , ( key , existingValue ) =>
637+ {
638+ if ( existingValue . GetType ( ) == typeof ( List < object > ) )
639+ {
640+ return ( ( List < object > ) existingValue ) . Concat ( new [ ] { arg . Value } ) . ToList ( ) ;
641+ }
642+
643+ return new List < object > ( ) { existingValue , arg . Value } ;
644+ } ) ;
645+ }
646+ else
647+ {
648+ dict . AddOrUpdate ( arg . Key , arg . Value , ( key , existingValue ) => arg . Value ) ;
649+ }
571650 }
572651 }
573652
0 commit comments