commandline icon indicating copy to clipboard operation
commandline copied to clipboard

Construction of immutable options objects fail in certain cultures

Open yaakov-h opened this issue 3 years ago • 0 comments

This is the same issue mentioned by brian-reichle in #188.

Given the following .NET 6 application:

using CommandLine;
using System.Globalization;

if (args.Length == 0)
{
    Console.Error.WriteLine("Missing command line argument parameter for culture code.");
    return -1;
}

var culture = CultureInfo.GetCultureInfoByIetfLanguageTag(args[0]);
Thread.CurrentThread.CurrentCulture = culture;

Console.WriteLine($"Using culture {culture.IetfLanguageTag}");

return Parser.Default.ParseArguments<MyOptions>(args.Skip(1))
    .MapResult(
        o =>
        {
            Console.WriteLine($"The integer is {o.Integer}");
            return 0;
        },
        err => -2);

class MyOptions
{
    public MyOptions(int integer)
    {
        Integer = integer;
    }

    [Option('i')]
    public int Integer { get; }
}

Running this with en-US works as expected, whilst running it with tr-TR crashes:

With no arguments:

PS C:\Data\Temp\cliargs-cultured\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0> .\ConsoleApp1.exe
Missing command line argument parameter for culture code.

In US English:

PS C:\Data\Temp\cliargs-cultured\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0> .\ConsoleApp1.exe en-US
Using culture en-US
The integer is 0

In Turkish:

PS C:\Data\Temp\cliargs-cultured\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0> .\ConsoleApp1.exe tr-TR
Using culture tr-TR
Unhandled exception. System.InvalidOperationException: Type MyOptions appears to be Immutable with invalid constructor. Check that constructor arguments have the same name and order of their underlying Type.  Constructor Parameters can be ordered as: '(integer)'
   at CommandLine.Core.InstanceBuilder.BuildImmutable[T](Type typeInfo, Maybe`1 factory, IEnumerable`1 specProps, IEnumerable`1 specPropsWithValue, List`1 setPropertyErrors)
   at CommandLine.Core.InstanceBuilder.<>c__DisplayClass0_0`1.<Build>b__5()
   at CommandLine.Core.InstanceBuilder.Build[T](Maybe`1 factory, Func`3 tokenizer, IEnumerable`1 arguments, StringComparer nameComparer, Boolean ignoreValueCase, CultureInfo parsingCulture, Boolean autoHelp, Boolean autoVersion, IEnumerable`1 nonFatalErrors)
   at CommandLine.Parser.ParseArguments[T](IEnumerable`1 args)
   at Program.<Main>$(String[] args) in C:\Data\Temp\cliargs-cultured\ConsoleApp1\ConsoleApp1\Program.cs:line 15
PS C:\Data\Temp\cliargs-cultured\ConsoleApp1\ConsoleApp1\bin\Debug\net6.0>

Interestingly the error message from the Turkish case says that my constructor parameters should be ordered as (integer), which clearly it already is.

I believe this is due to the lowercasing to the leading capital I in the options object's properties.

With tr-TR, I does not get lowercased to i as one might expect, but it gets lowercased to ı.

I believe this is due to the use of ToLower() here, rather than ToLowerInvariant() as seen elsewhere in the file.

yaakov-h avatar Feb 10 '22 04:02 yaakov-h