-
Notifications
You must be signed in to change notification settings - Fork 289
Closed
Description
Example:
class SameOptionAndPosValueArgs
{
[Option('u', "unit")]
public string OptValue { get; set; }
[Value(0)]
public string PosValue { get; set; }
}
[Fact]
public void SameOptionAndPosValue()
{
var parser = Parser.Default;
var result = parser.ParseArguments<SameOptionAndPosValueArgs>(
new[] { "arg", "-u", "arg" }); // !!! pos and value are "arg"
result
.WithNotParsed(errors => { throw new InvalidOperationException("Must be parsed."); })
.WithParsed(args =>
{
Assert.Equal("arg", args.OptValue);
Assert.Equal("arg", args.PosValue); // !!! args.PosValue is null
});
}
When user enters same values for [Option] and [Value] args, parser is losing one of it because they are equal tokens.
TokenPartitioner.cs has code:
var nonOptions = tokenList
.Where(t => !switches.Contains(t))
.Where(t => !scalars.Contains(t))
.Where(t => !sequences.Contains(t)).Memorize();
var values = nonOptions.Where(v => v.IsValue()).Memorize();
var errors = nonOptions.Except(values).Memorize();
One of tokens for "-u" option is already in scalars
variable so Where
is filtering out both tokens with "arg" and then its not gettings into values
. Filtering is happening because all tokens classes have IEqualtable<T>
so "arg" == "arg" but it is two different items in memory.
One of solutions: make reference comparing, not IEqutable<T>
. .Net doesn't have such comparer. Stackoverflow helps:
internal sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object>
{
public static readonly ReferenceEqualityComparer Default = new ReferenceEqualityComparer();
public new bool Equals(object x, object y)
{
return x == y; // reference equality because operator== is static and resolved at compile-time
}
public int GetHashCode(object obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
Pass this comparer to Contains
and Except
:
var nonOptions = tokenList
.Where(t => !switches.Contains(t, ReferenceEqualityComparer.Default))
.Where(t => !scalars.Contains(t, ReferenceEqualityComparer.Default))
.Where(t => !sequences.Contains(t, ReferenceEqualityComparer.Default)).Memorize();
var values = nonOptions.Where(v => v.IsValue()).Memorize();
var errors = nonOptions.Except(values, ReferenceEqualityComparer.Default).Cast<Token>().Memorize();
Metadata
Metadata
Assignees
Labels
No labels