@@ -227,7 +227,7 @@ bool TryGetInvokeArguments(ParameterInfo[] parameters, string?[] args, int argsO
227227 }
228228 }
229229
230- var argumentDictionary = ParseArgument ( args , argsOffset , optionTypeByOptionName ) ;
230+ var ( argumentDictionary , optionByIndex ) = ParseArgument ( args , argsOffset , optionTypeByOptionName ) ;
231231 invokeArgs = new object [ parameters . Length ] ;
232232
233233 for ( int i = 0 ; i < parameters . Length ; i ++ )
@@ -237,14 +237,24 @@ bool TryGetInvokeArguments(ParameterInfo[] parameters, string?[] args, int argsO
237237 if ( ! string . IsNullOrWhiteSpace ( option ? . ShortName ) && char . IsDigit ( option ! . ShortName , 0 ) ) throw new InvalidOperationException ( $ "Option '{ item . Name } ' has a short name, but the short name must start with A-Z or a-z.") ;
238238
239239 var value = default ( OptionParameter ) ;
240+
241+ // Indexed arguments (e.g. [Option(0)])
240242 if ( option != null && option . Index != - 1 )
241243 {
242- if ( argsOffset + i < args . Length )
244+ if ( optionByIndex . Count <= option . Index )
243245 {
244- value = new OptionParameter { Value = args [ argsOffset + i ] } ;
246+ if ( ! item . HasDefaultValue )
247+ {
248+ throw new InvalidOperationException ( $ "Required argument { option . Index } was not found in specified arguments.") ;
249+ }
250+ }
251+ else
252+ {
253+ value = optionByIndex [ option . Index ] ;
245254 }
246255 }
247256
257+ // Keyed options (e.g. -foo -bar )
248258 if ( value . Value != null || argumentDictionary . TryGetValue ( item . Name , out value ) || argumentDictionary . TryGetValue ( option ? . ShortName ? . TrimStart ( '-' ) ?? "" , out value ) )
249259 {
250260 if ( parameters [ i ] . ParameterType == typeof ( bool ) && value . Value == null )
@@ -361,18 +371,20 @@ bool TryGetInvokeArguments(ParameterInfo[] parameters, string?[] args, int argsO
361371 return null ;
362372 }
363373
364- static ReadOnlyDictionary < string , OptionParameter > ParseArgument ( string ? [ ] args , int argsOffset , IReadOnlyDictionary < string , Type > optionTypeByName )
374+ static ( ReadOnlyDictionary < string , OptionParameter > OptionByKey , IReadOnlyList < OptionParameter > OptionByIndex ) ParseArgument ( string ? [ ] args , int argsOffset , IReadOnlyDictionary < string , Type > optionTypeByName )
365375 {
366376 var dict = new Dictionary < string , OptionParameter > ( args . Length , StringComparer . OrdinalIgnoreCase ) ;
377+ var options = new List < OptionParameter > ( ) ;
367378 for ( int i = argsOffset ; i < args . Length ; )
368379 {
369- var key = args [ i ++ ] ;
370- if ( key is null || ! key . StartsWith ( "-" ) )
380+ var arg = args [ i ++ ] ;
381+ if ( arg is null || ! arg . StartsWith ( "-" ) )
371382 {
383+ options . Add ( new OptionParameter ( ) { Value = arg } ) ;
372384 continue ; // not key
373385 }
374386
375- key = key . TrimStart ( '-' ) ;
387+ var key = arg . TrimStart ( '-' ) ;
376388
377389 if ( optionTypeByName . TryGetValue ( key , out var optionType ) )
378390 {
@@ -387,9 +399,14 @@ static ReadOnlyDictionary<string, OptionParameter> ParseArgument(string?[] args,
387399 i ++ ;
388400 }
389401 }
402+ else
403+ {
404+ // not key
405+ options . Add ( new OptionParameter ( ) { Value = arg } ) ;
406+ }
390407 }
391408
392- return new ReadOnlyDictionary < string , OptionParameter > ( dict ) ;
409+ return ( new ReadOnlyDictionary < string , OptionParameter > ( dict ) , options ) ;
393410 }
394411
395412 struct OptionParameter
0 commit comments