diff --git a/src/CommandLine/CommandLine.csproj b/src/CommandLine/CommandLine.csproj index 04496eb8..7330ba26 100644 --- a/src/CommandLine/CommandLine.csproj +++ b/src/CommandLine/CommandLine.csproj @@ -3,7 +3,7 @@ CommandLine Library - netstandard2.0;net40;net45;net461 + netstandard2.0;net40;net45;net461;net7 $(DefineConstants);CSX_EITHER_INTERNAL;CSX_REM_EITHER_BEYOND_2;CSX_ENUM_INTERNAL;ERRH_INTERNAL;CSX_MAYBE_INTERNAL;CSX_REM_EITHER_FUNC;CSX_REM_CRYPTORAND;ERRH_ADD_MAYBE_METHODS $(DefineConstants);SKIP_FSHARP true diff --git a/src/CommandLine/Core/Specification.cs b/src/CommandLine/Core/Specification.cs index b95b998c..8a093b94 100644 --- a/src/CommandLine/Core/Specification.cs +++ b/src/CommandLine/Core/Specification.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using CommandLine.Infrastructure; using CSharpx; @@ -54,7 +56,7 @@ protected Specification(SpecificationType tag, bool required, Maybe min, Ma this.hidden = hidden; } - public SpecificationType Tag + public SpecificationType Tag { get { return tag; } } @@ -110,28 +112,40 @@ public bool Hidden } public static Specification FromProperty(PropertyInfo property) - { + { var attrs = property.GetCustomAttributes(true); + +#if NET7_0_OR_GREATER + var isRequired = attrs.OfType().Any(); +#else + var isRequired = false; +#endif + var oa = attrs.OfType(); if (oa.Count() == 1) { - var spec = OptionSpecification.FromAttribute(oa.Single(), property.PropertyType, - ReflectionHelper.GetNamesOfEnum(property.PropertyType)); + var optionAttribute = oa.Single(); + optionAttribute.Required |= isRequired; + var spec = OptionSpecification.FromAttribute(optionAttribute, property.PropertyType, + ReflectionHelper.GetNamesOfEnum(property.PropertyType)); if (spec.ShortName.Length == 0 && spec.LongName.Length == 0) { return spec.WithLongName(property.Name.ToLowerInvariant()); } + return spec; } var va = attrs.OfType(); if (va.Count() == 1) { - return ValueSpecification.FromAttribute(va.Single(), property.PropertyType, - property.PropertyType.GetTypeInfo().IsEnum - ? Enum.GetNames(property.PropertyType) - : Enumerable.Empty()); + var valueAttribute = va.Single(); + valueAttribute.Required |= isRequired; + return ValueSpecification.FromAttribute(valueAttribute, property.PropertyType, + property.PropertyType.GetTypeInfo().IsEnum + ? Enum.GetNames(property.PropertyType) + : Enumerable.Empty()); } throw new InvalidOperationException(); diff --git a/src/CommandLine/Core/TokenPartitioner.cs b/src/CommandLine/Core/TokenPartitioner.cs index 4dc25f7f..eee5b538 100644 --- a/src/CommandLine/Core/TokenPartitioner.cs +++ b/src/CommandLine/Core/TokenPartitioner.cs @@ -15,8 +15,6 @@ Tuple>>, IEnumerable tokens, Func> typeLookup) { - IEqualityComparer tokenComparer = ReferenceEqualityComparer.Default; - var tokenList = tokens.Memoize(); var partitioned = PartitionTokensByType(tokenList, typeLookup); var switches = partitioned.Item1; diff --git a/tests/CommandLine.Tests/CommandLine.Tests.csproj b/tests/CommandLine.Tests/CommandLine.Tests.csproj index d4dbcab0..dc373b67 100644 --- a/tests/CommandLine.Tests/CommandLine.Tests.csproj +++ b/tests/CommandLine.Tests/CommandLine.Tests.csproj @@ -2,7 +2,7 @@ Library - net461;netcoreapp3.1 + net461;net7;netcoreapp3.1 $(DefineConstants);SKIP_FSHARP ..\..\CommandLine.snk true diff --git a/tests/CommandLine.Tests/Unit/Issue862Tests.cs b/tests/CommandLine.Tests/Unit/Issue862Tests.cs new file mode 100644 index 00000000..9dcd574d --- /dev/null +++ b/tests/CommandLine.Tests/Unit/Issue862Tests.cs @@ -0,0 +1,29 @@ +using System; +using FluentAssertions; +using Xunit; + +namespace CommandLine.Tests.Unit +{ + #if NET7_0_OR_GREATER + public class Issue862Tests + { + + [Fact] + public void Properties_with_required_modifier_are_required() + { + var arguments = Array.Empty(); + var result = new Parser().ParseArguments(arguments); + + result.Errors.Should().ContainSingle(e => e.Tag == ErrorType.MissingRequiredOptionError); + result.Tag.Should().Be(ParserResultType.NotParsed); + } + + private class Options + { + [Option("cols")] + public required int Cols { get; set; } + } + } + + #endif +}