Megosztás a következőn keresztül:


Argumentumok kötése a kezelőkhöz a következő helyen: System.CommandLine

Fontos

System.CommandLine jelenleg előzetes verzióban érhető el, és ez a dokumentáció a 2.0-s bétaverzió 4-es verziójához készült. Egyes információk az előzetes termékre vonatkoznak, amelyek a kiadás előtt jelentősen módosíthatók. A Microsoft nem vállal kifejezett vagy törvényi garanciát az itt megjelenő információért.

Az argumentumok elemzésének és parancskezelő kódhoz való biztosításának folyamatát paraméterkötésnek nevezzük. System.CommandLine számos beépített argumentumtípus kötésére képes. Például egész számokat, számokat és fájlrendszer-objektumokat, például FileInfo és DirectoryInfo lehet kötni. Több System.CommandLine típus is köthető.

Beépített argumentumérvényesítés

Az argumentumok típust és aritást várnak. System.CommandLine elutasítja azokat az argumentumokat, amelyek nem felelnek meg ezeknek az elvárásoknak.

Például elemzési hiba jelenik meg, ha az egész szám lehetőség argumentuma nem egész szám.

myapp --delay not-an-int
Cannot parse argument 'not-an-int' as System.Int32.

A rendszer aritási hibát jelenít meg, ha több argumentumot ad át egy olyan beállításnak, amelynek maximális aritása egy:

myapp --delay-option 1 --delay-option 2
Option '--delay' expects a single argument but 2 were provided.

Ezt a viselkedést felülbíráltathatja a következő beállítással Option.AllowMultipleArgumentsPerTokentrue: . Ebben az esetben megismételhet egy olyan beállítást, amelynek maximális aritása egy, de csak a sor utolsó értéke fogadható el. Az alábbi példában az érték three az alkalmazásnak lesz átadva.

myapp --item one --item two --item three

Paraméterkötés legfeljebb 8 lehetőség és argumentum

Az alábbi példa bemutatja, hogyan lehet a parancskezelő paramétereihez kötési beállításokat meghívni SetHandler:

var delayOption = new Option<int>
    ("--delay", "An option whose argument is parsed as an int.");
var messageOption = new Option<string>
    ("--message", "An option whose argument is parsed as a string.");

var rootCommand = new RootCommand("Parameter binding example");
rootCommand.Add(delayOption);
rootCommand.Add(messageOption);

rootCommand.SetHandler(
    (delayOptionValue, messageOptionValue) =>
    {
        DisplayIntAndString(delayOptionValue, messageOptionValue);
    },
    delayOption, messageOption);

await rootCommand.InvokeAsync(args);
public static void DisplayIntAndString(int delayOptionValue, string messageOptionValue)
{
    Console.WriteLine($"--delay = {delayOptionValue}");
    Console.WriteLine($"--message = {messageOptionValue}");
}

A lambda paraméterek olyan változók, amelyek a lehetőségek és argumentumok értékeit jelölik:

(delayOptionValue, messageOptionValue) =>
{
    DisplayIntAndString(delayOptionValue, messageOptionValue);
},

A lambdát követő változók a beállítás és az argumentumértékek forrását képező beállítás- és argumentumobjektumokat jelölik:

delayOption, messageOption);

A lehetőségeket és argumentumokat ugyanabban a sorrendben kell deklarálni a lambdában és a lambdát követő paraméterekben. Ha a sorrend nem konzisztens, a következő forgatókönyvek egyikét fogja eredményezni:

  • Ha a rendelésen kívüli beállítások vagy argumentumok különböző típusúak, a rendszer futásidejű kivételt ad ki. Előfordulhat például, hogy egy int forrás szerepel string a források listájában.
  • Ha a rendelésen kívüli beállítások vagy argumentumok azonos típusúak, a kezelő csendesen rossz értékeket kap a megadott paraméterekben. Előfordulhat például, hogy a beállítás x ott jelenik meg, string ahol string a lehetőségnek y szerepelnie kell a források listájában. Ebben az esetben a beállításérték y változója megkapja a beállítás x értékét.

A túlterhelések SetHandler legfeljebb 8 paramétert támogatnak szinkron és aszinkron aláírásokkal.

Több mint 8 beállítás és argumentum paraméterkötése

Több mint 8 beállítás kezeléséhez vagy egy egyéni típus több beállításból való létrehozásához használhat InvocationContext egyéni kötést vagy egyéni kötést.

Használja a következő parancsot: InvocationContext

A SetHandler túlterhelés hozzáférést biztosít az InvocationContext objektumhoz, és tetszőleges számú beállítás- és argumentumérték lekérésére használható InvocationContext . Példák: Kilépési kódok beállítása és Leállítás kezelése.

Egyéni iratgyűjtő használata

Az egyéni kötések lehetővé teszi, hogy több beállítás- vagy argumentumértéket kombináljon összetett típusba, és ezt egyetlen kezelőparaméterbe adja át. Tegyük fel, hogy van egy Person típusa:

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

Hozzon létre egy osztályt, amely T a BinderBase<T>parancssori bemenet alapján létrehozandó típus:

public class PersonBinder : BinderBase<Person>
{
    private readonly Option<string> _firstNameOption;
    private readonly Option<string> _lastNameOption;

    public PersonBinder(Option<string> firstNameOption, Option<string> lastNameOption)
    {
        _firstNameOption = firstNameOption;
        _lastNameOption = lastNameOption;
    }

    protected override Person GetBoundValue(BindingContext bindingContext) =>
        new Person
        {
            FirstName = bindingContext.ParseResult.GetValueForOption(_firstNameOption),
            LastName = bindingContext.ParseResult.GetValueForOption(_lastNameOption)
        };
}

Az egyéni iratgyűjtővel ugyanúgy továbbíthatja az egyéni típust a kezelőnek, mint a beállítások és argumentumok értékeit:

rootCommand.SetHandler((fileOptionValue, person) =>
    {
        DoRootCommand(fileOptionValue, person);
    },
    fileOption, new PersonBinder(firstNameOption, lastNameOption));

Íme a teljes program, amelyből az előző példák származnak:

using System.CommandLine;
using System.CommandLine.Binding;

public class Program
{
    internal static async Task Main(string[] args)
    {
        var fileOption = new Option<FileInfo?>(
              name: "--file",
              description: "An option whose argument is parsed as a FileInfo",
              getDefaultValue: () => new FileInfo("scl.runtimeconfig.json"));

        var firstNameOption = new Option<string>(
              name: "--first-name",
              description: "Person.FirstName");

        var lastNameOption = new Option<string>(
              name: "--last-name",
              description: "Person.LastName");

        var rootCommand = new RootCommand();
        rootCommand.Add(fileOption);
        rootCommand.Add(firstNameOption);
        rootCommand.Add(lastNameOption);

        rootCommand.SetHandler((fileOptionValue, person) =>
            {
                DoRootCommand(fileOptionValue, person);
            },
            fileOption, new PersonBinder(firstNameOption, lastNameOption));

        await rootCommand.InvokeAsync(args);
    }

    public static void DoRootCommand(FileInfo? aFile, Person aPerson)
    {
        Console.WriteLine($"File = {aFile?.FullName}");
        Console.WriteLine($"Person = {aPerson?.FirstName} {aPerson?.LastName}");
    }

    public class Person
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
    }

    public class PersonBinder : BinderBase<Person>
    {
        private readonly Option<string> _firstNameOption;
        private readonly Option<string> _lastNameOption;

        public PersonBinder(Option<string> firstNameOption, Option<string> lastNameOption)
        {
            _firstNameOption = firstNameOption;
            _lastNameOption = lastNameOption;
        }

        protected override Person GetBoundValue(BindingContext bindingContext) =>
            new Person
            {
                FirstName = bindingContext.ParseResult.GetValueForOption(_firstNameOption),
                LastName = bindingContext.ParseResult.GetValueForOption(_lastNameOption)
            };
    }
}

Kilépési kódok beállítása

Vannak Task-visszatérő Func túlterhelések SetHandler. Ha a kezelő aszinkron kódból van meghívva, egy olyan kezelőtől kaphat vissza, Task<int> amely az egyiket használja, és az int érték használatával állítja be a folyamat kilépési kódját, ahogyan az alábbi példában is látható:

static async Task<int> Main(string[] args)
{
    var delayOption = new Option<int>("--delay");
    var messageOption = new Option<string>("--message");

    var rootCommand = new RootCommand("Parameter binding example");
    rootCommand.Add(delayOption);
    rootCommand.Add(messageOption);

    rootCommand.SetHandler((delayOptionValue, messageOptionValue) =>
        {
            Console.WriteLine($"--delay = {delayOptionValue}");
            Console.WriteLine($"--message = {messageOptionValue}");
            return Task.FromResult(100);
        },
        delayOption, messageOption);

    return await rootCommand.InvokeAsync(args);
}

Ha azonban magának a lambdának aszinkronnak kell lennie, nem adhat vissza egy Task<int>. Ebben az esetben használja a .InvocationContext.ExitCode A lambdába injektált példányt egy SetHandler-túlterheléssel lehet beszúrni InvocationContext , amely az InvocationContext egyetlen paramétert adja meg. Ez a SetHandler túlterhelés nem teszi lehetővé az objektumok megadásátIValueDescriptor<T>, de az alábbi példában látható módon a ParseResult tulajdonságból InvocationContextis lekérheti a beállítás- és argumentumértékeket:

static async Task<int> Main(string[] args)
{
    var delayOption = new Option<int>("--delay");
    var messageOption = new Option<string>("--message");

    var rootCommand = new RootCommand("Parameter binding example");
    rootCommand.Add(delayOption);
    rootCommand.Add(messageOption);

    rootCommand.SetHandler(async (context) =>
        {
            int delayOptionValue = context.ParseResult.GetValueForOption(delayOption);
            string? messageOptionValue = context.ParseResult.GetValueForOption(messageOption);
        
            Console.WriteLine($"--delay = {delayOptionValue}");
            await Task.Delay(delayOptionValue);
            Console.WriteLine($"--message = {messageOptionValue}");
            context.ExitCode = 100;
        });

    return await rootCommand.InvokeAsync(args);
}

Ha nincs aszinkron munkája, használhatja a Action túlterheléseket. Ebben az esetben állítsa be a kilépési kódot InvocationContext.ExitCode ugyanúgy, mint egy aszinkron lambdával.

A kilépési kód alapértelmezés szerint 1. Ha nem állítja be explicit módon, az értéke 0 lesz, amikor a kezelő normál módon kilép. Kivétel esetén megtartja az alapértelmezett értéket.

Támogatott típusok

Az alábbi példák olyan kódot mutatnak be, amely bizonyos gyakran használt típusokat köt össze.

Enumerációk

A típusok értékeit enum név köti össze, a kötés pedig a kis- és nagybetűk érzéketlensége:

var colorOption = new Option<ConsoleColor>("--color");

var rootCommand = new RootCommand("Enum binding example");
rootCommand.Add(colorOption);

rootCommand.SetHandler((colorOptionValue) =>
    { Console.WriteLine(colorOptionValue); },
    colorOption);

await rootCommand.InvokeAsync(args);

Íme egy példa parancssori bemenetre és az előző példából származó kimenetre:

myapp --color red
myapp --color RED
Red
Red

Tömbök és listák

Számos gyakori implementálási IEnumerable típus támogatott. Példa:

var itemsOption = new Option<IEnumerable<string>>("--items")
    { AllowMultipleArgumentsPerToken = true };

var command = new RootCommand("IEnumerable binding example");
command.Add(itemsOption);

command.SetHandler((items) =>
    {
        Console.WriteLine(items.GetType());

        foreach (string item in items)
        {
            Console.WriteLine(item);
        }
    },
    itemsOption);

await command.InvokeAsync(args);

Íme egy példa parancssori bemenetre és az előző példából származó kimenetre:

--items one --items two --items three
System.Collections.Generic.List`1[System.String]
one
two
three

Mivel AllowMultipleArgumentsPerToken a beállítás értéke truea következő, a következő bemenet ugyanazt a kimenetet eredményezi:

--items one two three

Fájlrendszertípusok

A fájlrendszerrel működő parancssori alkalmazások használhatják a , FileInfoés DirectoryInfo a FileSystemInfotípusokat. Az alábbi példa a következő használatát FileSystemInfomutatja be:

var fileOrDirectoryOption = new Option<FileSystemInfo>("--file-or-directory");

var command = new RootCommand();
command.Add(fileOrDirectoryOption);

command.SetHandler((fileSystemInfo) =>
    {
        switch (fileSystemInfo)
        {
            case FileInfo file                    :
                Console.WriteLine($"File name: {file.FullName}");
                break;
            case DirectoryInfo directory:
                Console.WriteLine($"Directory name: {directory.FullName}");
                break;
            default:
                Console.WriteLine("Not a valid file or directory name.");
                break;
        }
    },
    fileOrDirectoryOption);

await command.InvokeAsync(args);

A következővel FileInfo és DirectoryInfo a mintaegyeztetési kód nem szükséges:

var fileOption = new Option<FileInfo>("--file");

var command = new RootCommand();
command.Add(fileOption);

command.SetHandler((file) =>
    {
        if (file is not null)
        {
            Console.WriteLine($"File name: {file?.FullName}");
        }
        else
        {
            Console.WriteLine("Not a valid file name.");
        }
    },
    fileOption);

await command.InvokeAsync(args);

Egyéb támogatott típusok

Sok olyan típus, amely egyetlen sztringparamétert használó konstruktorsal rendelkezik, így kötött lehet. Például az olyan kód, amely inkább egy Uri kóddal FileInfo működik együtt.

var endpointOption = new Option<Uri>("--endpoint");

var command = new RootCommand();
command.Add(endpointOption);

command.SetHandler((uri) =>
    {
        Console.WriteLine($"URL: {uri?.ToString()}");
    },
    endpointOption);

await command.InvokeAsync(args);

A fájlrendszertípusok Urimellett a következő típusok támogatottak:

  • bool
  • byte
  • DateTime
  • DateTimeOffset
  • decimal
  • double
  • float
  • Guid
  • int
  • long
  • sbyte
  • short
  • uint
  • ulong
  • ushort

Objektumok használata System.CommandLine

Van egy SetHandler túlterhelés, amely hozzáférést biztosít az InvocationContext objektumhoz. Ez az objektum ezután más System.CommandLine objektumok elérésére is használható. Például a következő objektumokhoz férhet hozzá:

InvocationContext

Példák: Kilépési kódok beállítása és Leállítás kezelése.

CancellationToken

A használat CancellationTokenmódjával kapcsolatos információkért tekintse meg a felmondás kezelését ismertető témakört.

IConsole

IConsole a tesztelést és számos bővíthetőségi forgatókönyvet egyszerűbbé teszi, mint a használatát System.Console. A tulajdonságban InvocationContext.Console elérhető.

ParseResult

Az ParseResult objektum elérhető a InvocationContext.ParseResult tulajdonságban. Ez egy szimpla struktúra, amely a parancssori bemenet elemzésének eredményeit jelöli. Ezzel ellenőrizheti, hogy vannak-e lehetőségek vagy argumentumok a parancssorban, vagy lekérheti a tulajdonságot ParseResult.UnmatchedTokens . Ez a tulajdonság az elemezett jogkivonatok listáját tartalmazza, de nem felelt meg a konfigurált parancsoknak , beállításoknak vagy argumentumoknak.

A nem egyező jogkivonatok listája olyan parancsokban hasznos, amelyek burkolóként viselkednek. A burkolóparancsok jogkivonatokat vesznek fel, és továbbítják őket egy másik parancsnak vagy alkalmazásnak. A sudo linuxos parancs egy példa. Egy felhasználó nevét veszi fel a megszemélyesítéshez, majd egy parancs futtatásához. Példa:

sudo -u admin apt update

Ez a apt update parancssor felhasználóként futtatná a adminparancsot.

Egy ilyen burkolóparancs implementálásához állítsa a parancs tulajdonságát TreatUnmatchedTokensAsErrors a következőre false: . Ezután a ParseResult.UnmatchedTokens tulajdonság tartalmazni fogja az összes olyan argumentumot, amely nem tartozik explicit módon a parancshoz. Az előző példában ParseResult.UnmatchedTokens a jogkivonatokat és update a apt jogkivonatokat tartalmazza. A parancskezelő ezután továbbíthatja a UnmatchedTokens parancsot egy új rendszerhéj-meghívásnak, például.

Egyéni ellenőrzés és kötés

Egyéni érvényesítési kód megadásához hívja meg AddValidator a parancsot, a beállítást vagy az argumentumot az alábbi példában látható módon:

var delayOption = new Option<int>("--delay");
delayOption.AddValidator(result =>
{
    if (result.GetValueForOption(delayOption) < 1)
    {
        result.ErrorMessage = "Must be greater than 0";
    }
});

Ha elemezni és ellenőrizni szeretné a bemenetet, használjon delegáltat ParseArgument<T> az alábbi példában látható módon:

var delayOption = new Option<int>(
      name: "--delay",
      description: "An option whose argument is parsed as an int.",
      isDefault: true,
      parseArgument: result =>
      {
          if (!result.Tokens.Any())
          {
              return 42;
          }

          if (int.TryParse(result.Tokens.Single().Value, out var delay))
          {
              if (delay < 1)
              {
                  result.ErrorMessage = "Must be greater than 0";
              }
              return delay;
          }
          else
          {
              result.ErrorMessage = "Not an int.";
              return 0; // Ignored.
          }
      });

Az előző kód úgy van beadva isDefaulttrue , hogy a parseArgument meghatalmazott akkor is meghívva legyen, ha a felhasználó nem adott meg értéket ehhez a beállításhoz.

Íme néhány példa arra, hogy mit tehet a következőkkel ParseArgument<T>AddValidator:

  • Egyéni típusok elemzése, például az Person osztály az alábbi példában:

    public class Person
    {
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
    }
    
    var personOption = new Option<Person?>(
          name: "--person",
          description: "An option whose argument is parsed as a Person",
          parseArgument: result =>
          {
              if (result.Tokens.Count != 2)
              {
                  result.ErrorMessage = "--person requires two arguments";
                  return null;
              }
              return new Person
              {
                  FirstName = result.Tokens.First().Value,
                  LastName = result.Tokens.Last().Value
              };
          })
    {
        Arity = ArgumentArity.OneOrMore,
        AllowMultipleArgumentsPerToken = true
    };
    
  • Más típusú bemeneti sztringek elemzése (például az "1,2,3" elem elemzése).int[]

  • Dinamikus aritás. Van például két argumentuma, amelyek sztringtömbökként vannak definiálva, és a parancssori bemenetben sztringek sorozatát kell kezelnie. A ArgumentResult.OnlyTake metódus lehetővé teszi a bemeneti sztringek dinamikus felosztását az argumentumok között.

Lásd még

System.CommandLine Áttekintés