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 szerepelstring
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
aholstring
a lehetőségneky
szerepelnie kell a források listájában. Ebben az esetben a beállításértéky
változója megkapja a beállításx
é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 InvocationContext
is 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 true
a 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 FileSystemInfo
mutatja 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 Uri
mellett 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 admin
parancsot.
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 isDefault
true
, 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.