commandline icon indicating copy to clipboard operation
commandline copied to clipboard

InvalidCastException in GetUsageData when using nullable reference types

Open rubberduck203 opened this issue 4 years ago • 8 comments

https://github.com/rubberduck203/GitNStats/issues/27

I recently enabled nullable reference types for my application. Since then, calling my app with the --help flag has started failing with an unhandled exception.

$ dotnet run --project src/gitnstats/gitnstats.csproj -- --help
Unhandled exception. System.InvalidCastException: Unable to cast object of type 'System.Runtime.CompilerServices.NullableAttribute' to type 'CommandLine.Text.UsageAttribute'.
   at CommandLine.Core.ReflectionExtensions.<>c.<GetUsageData>b__2_3(<>f__AnonymousType1`2 <>h__TransparentIdentifier0)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at CommandLine.Core.ReflectionExtensions.GetUsageData(Type type)
   at CommandLine.Text.HelpText.GetUsageFromType(Type type)
   at CommandLine.Text.HelpText.RenderUsageTextAsLines[T](ParserResult`1 parserResult, Func`2 mapperFunc)+MoveNext()
   at CSharpx.EnumerableExtensions.ToMaybe[T](IEnumerable`1 source)
   at CommandLine.Text.HelpText.AutoBuild[T](ParserResult`1 parserResult, Func`2 onError, Func`2 onExample, Boolean verbsIndex, Int32 maxDisplayWidth)
   at CommandLine.Text.HelpText.AutoBuild[T](ParserResult`1 parserResult, Func`2 onError, Int32 maxDisplayWidth)
   at CommandLine.Text.HelpText.AutoBuild[T](ParserResult`1 parserResult, Int32 maxDisplayWidth)
   at CommandLine.Parser.<>c__DisplayClass17_0`1.<DisplayHelp>b__1(IEnumerable`1 _, TextWriter writer)
   at CSharpx.MaybeExtensions.Do[T1,T2](Maybe`1 maybe, Action`2 action)
   at CommandLine.Parser.<>c__DisplayClass17_0`1.<DisplayHelp>b__0(IEnumerable`1 errors)
   at CommandLine.ParserResultExtensions.WithNotParsed[T](ParserResult`1 result, Action`1 action)
   at CommandLine.Parser.DisplayHelp[T](ParserResult`1 parserResult, TextWriter helpWriter, Int32 maxDisplayWidth)
   at CommandLine.Parser.MakeParserResult[T](ParserResult`1 parserResult, ParserSettings settings)
   at CommandLine.Parser.ParseArguments[T](IEnumerable`1 args)
   at GitNStats.Program.Main(String[] args) in /Users/rubberduck/src/GitNStats/src/gitnstats/Program.cs:line 11

The invalid cast is occurring in this block of code.

https://github.com/commandlineparser/commandline/blob/d443a51aeb3a418425e970542b3b96e9da5f62e2/src/CommandLine/Core/ReflectionExtensions.cs#L39-L48

I haven't figured out if it's occurring on line 44 or 45 yet, but GetUsageData seems to be assuming that it will only find a single attribute.

I'll do my best to update this with a minimal reproduction.

rubberduck203 avatar Nov 21 '20 11:11 rubberduck203

Minimal reproduction can be found here: https://github.com/rubberduck203/commandline/commit/90ccab813e6fa5b004ffd4cf601375e32bca6093

In the test project file, enable nullable reference types This means the tests can not target net461, so we need a separate test project.

<nullable>enable</nullable>

The options class must have a nullable property, then we need to add custom usage examples in order to trigger the bug.

    public class ReflectionExtensionsTests
    {
        [Fact]
        public void GetUsageDataDoesNotExplodeWhenUsedWithNullableReferenceTypesUsingTheUsageAttribute()
        {
            typeof(NullableReferenceTypeOptions).GetUsageData();
        }
    }

    public class NullableReferenceTypeOptions
    {
        [Option(HelpText = "Define a string value here.")]
        public string? StringValue { get; set; }

        [Usage]
        public static IEnumerable<Example> Examples 
        {
            get 
            {
                yield return new Example("Run on current directory", new NullableReferenceTypeOptions());
            }
        }
    }

rubberduck203 avatar Nov 21 '20 13:11 rubberduck203

I submitted PR #715 to fix this.

rubberduck203 avatar Nov 21 '20 14:11 rubberduck203

I just experienced this bug. It would be great if it could be resolved. Looking at the pull request that code change will fix the issue.

cpmcgrath avatar Apr 15 '21 04:04 cpmcgrath

I've experienced that issue too and it would be great if we can have a release of the fix !

mnivet avatar Dec 07 '21 15:12 mnivet

Still experiencing this same issue.

roa-nyx avatar Mar 07 '22 19:03 roa-nyx

The last commit to this repo was several months before I submitted the bug report & PR in 2020.

rubberduck203 avatar Mar 07 '22 20:03 rubberduck203

@ericnewton76 any chance a fix for this could be merged, possibly the open PR? We have run into the same issue with nullable options lately, and would very much prefer not to introduce workarounds.

Xitric avatar Jun 27 '22 11:06 Xitric

As a workaround you can wrap the offending property in a #nullable disable/#nullable restore pair

JohnNilsson avatar Mar 28 '23 21:03 JohnNilsson