içindeki işleyicilere bağımsız değişkenleri bağlama System.CommandLine
Önemli
System.CommandLine
şu anda ÖNİzLEME aşamasındadır ve bu belgeler 2.0 beta 4 sürümüne yöneliktir.
Bazı bilgiler, yayımlanmadan önce önemli ölçüde değiştirilebilen yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.
Bağımsız değişkenleri ayrıştırma ve komut işleyici koduna sağlama işlemine parametre bağlama adı verilir. System.CommandLine
yerleşik birçok bağımsız değişken türünü bağlama özelliğine sahiptir. Örneğin, ve gibi FileInfoDirectoryInfo tamsayılar, sabit listeleri ve dosya sistemi nesneleri bağlanabilir. Çeşitli System.CommandLine
türler de bağlanabilir.
Yerleşik bağımsız değişken doğrulama
Bağımsız değişkenlerin beklenen türleri ve arity'leri vardır. System.CommandLine
bu beklentilerle eşleşmeyen bağımsız değişkenleri reddeder.
Örneğin, bir tamsayı seçeneğinin bağımsız değişkeni tamsayı değilse ayrıştırma hatası görüntülenir.
myapp --delay not-an-int
Cannot parse argument 'not-an-int' as System.Int32.
Birden çok bağımsız değişken en fazla bir değere sahip bir seçeneğe geçirilirse bir arity hatası görüntülenir:
myapp --delay-option 1 --delay-option 2
Option '--delay' expects a single argument but 2 were provided.
bu davranış olarak ayarlanarak Option.AllowMultipleArgumentsPerTokentrue
geçersiz kılınabilir. Bu durumda, maksimum bir arity değerine sahip bir seçeneği yineleyebilirsiniz, ancak satırdaki yalnızca son değer kabul edilir. Aşağıdaki örnekte, değer three
uygulamaya geçirilir.
myapp --item one --item two --item three
8 seçeneğe ve bağımsız değişkene kadar parametre bağlama
Aşağıdaki örnekte, komutunu çağırarak SetHandlerseçeneklerin komut işleyici parametrelerine nasıl bağlandığı gösterilmektedir:
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}");
}
Lambda parametreleri, seçeneklerin ve bağımsız değişkenlerin değerlerini temsil eden değişkenlerdir:
(delayOptionValue, messageOptionValue) =>
{
DisplayIntAndString(delayOptionValue, messageOptionValue);
},
Lambda'yı izleyen değişkenler, seçenek ve bağımsız değişken değerlerinin kaynakları olan seçenek ve bağımsız değişken nesnelerini temsil eder:
delayOption, messageOption);
Seçenekler ve bağımsız değişkenler, lambda'da ve lambda'yı izleyen parametrelerde aynı sırada bildirilmelidir. Sıra tutarlı değilse aşağıdaki senaryolardan biri sonuçlanır:
- Sıra dışı seçenekler veya bağımsız değişkenler farklı türlerdeyse, bir çalışma zamanı özel durumu oluşturulur. Örneğin, kaynak
int
listesinde olması gereken birstring
görünebilir. - Sıra dışı seçenekler veya bağımsız değişkenler aynı türdeyse, işleyici ona sağlanan parametrelerde yanlış değerleri sessizce alır. Örneğin,
string
seçenekx
kaynak listesinde olması gereken yerdey
string
görünebilir. Bu durumda seçenek değerinin değişkeni seçeneky
x
değerini alır.
Hem zaman uyumlu hem de zaman uyumsuz imzalarla en fazla 8 parametreyi destekleyen aşırı yüklemeler SetHandler vardır.
Parametre bağlama 8'den fazla seçenek ve bağımsız değişken
8'den fazla seçeneği işlemek veya birden çok seçenekten özel bir tür oluşturmak için veya özel bağlayıcı kullanabilirsiniz InvocationContext
.
InvocationContext
komutunu kullanma
Aşırı SetHandler yükleme nesneye InvocationContext erişim sağlar ve istediğiniz sayıda seçenek ve bağımsız değişken değeri almak için kullanabilirsiniz InvocationContext
. Örnekler için bkz . Çıkış kodlarını ayarlama ve Sonlandırmayı işleme.
Özel bağlayıcı kullanma
Özel bağlayıcı, birden çok seçenek veya bağımsız değişken değerini karmaşık bir türde birleştirmenizi ve bunu tek bir işleyici parametresine geçirmenizi sağlar. Bir Person
türe sahip olduğunuzu varsayalım:
public class Person
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
komutundan BinderBase<T>türetilmiş bir sınıf oluşturun; burada T
komut satırı girişine göre oluşturulacak türdür:
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)
};
}
Özel bağlayıcı ile, özel türünüzün işleyicinize geçirilmesini, seçenekler ve bağımsız değişkenler için değerlerle aynı şekilde alabilirsiniz:
rootCommand.SetHandler((fileOptionValue, person) =>
{
DoRootCommand(fileOptionValue, person);
},
fileOption, new PersonBinder(firstNameOption, lastNameOption));
Yukarıdaki örneklerin alındığı programın tamamı aşağıda verilmiştir:
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)
};
}
}
Çıkış kodlarını ayarlama
Task- func aşırı yüklemeleri döndürülmektedirSetHandler. İşleyiciniz zaman uyumsuz koddan çağrılırsa, aşağıdaki örnekte olduğu gibi bunlardan birini kullanan bir işleyiciden döndürebilir Task<int>
ve işlem çıkış kodunu ayarlamak için değerini kullanabilirsiniz int
:
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);
}
Ancak lambdanın kendisinin zaman uyumsuz olması gerekiyorsa döndüremezsiniz Task<int>
. Bu durumda kullanın InvocationContext.ExitCode. Tek parametre olarak öğesini belirten InvocationContext
bir SetHandler aşırı yüklemesini kullanarak lambdanıza eklenen örneği alabilirsinizInvocationContext
. Bu SetHandler
aşırı yükleme nesneleri belirtmenize IValueDescriptor<T>
izin vermez, ancak aşağıdaki örnekte gösterildiği gibi öğesinin ParseResult özelliğinden InvocationContext
seçenek ve bağımsız değişken değerleri alabilirsiniz:
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);
}
Yapacak zaman uyumsuz işiniz yoksa, aşırı yüklemeleri kullanabilirsiniz Action . Bu durumda, çıkış kodunu InvocationContext.ExitCode
zaman uyumsuz lambda ile yaptığınız gibi ayarlayın.
Çıkış kodu varsayılan olarak 1'tir. Açıkça ayarlamazsanız, işleyiciniz normal şekilde çıktığında değeri 0 olarak ayarlanır. Özel durum oluşursa, varsayılan değeri korur.
Desteklenen türler
Aşağıdaki örneklerde yaygın olarak kullanılan bazı türleri bağlayan kod gösterilmektedir.
Numaralandırmalar
Türlerin enum
değerleri ada bağlıdır ve bağlama büyük/küçük harfe duyarsızdır:
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);
Aşağıdaki örnek komut satırı girişi ve yukarıdaki örnekten elde edilen çıkış:
myapp --color red
myapp --color RED
Red
Red
Diziler ve listeler
Uygulayan IEnumerable birçok yaygın tür desteklenir. Örneğin:
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);
Aşağıdaki örnek komut satırı girişi ve yukarıdaki örnekten elde edilen çıkış:
--items one --items two --items three
System.Collections.Generic.List`1[System.String]
one
two
three
AllowMultipleArgumentsPerToken olarak ayarlandığındantrue
, aşağıdaki giriş aynı çıkışla sonuçlanır:
--items one two three
Dosya sistemi türleri
Dosya sistemiyle çalışan komut satırı uygulamaları , FileInfove DirectoryInfo türlerini kullanabilirFileSystemInfo. Aşağıdaki örnekte kullanımı gösterilmektedir FileSystemInfo
:
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);
ile FileInfo
ve DirectoryInfo
desen eşleştirme kodu gerekli değildir:
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);
Desteklenen diğer türler
Tek bir dize parametresi alan bir oluşturucuya sahip birçok tür bu şekilde bağlanabilir. Örneğin, ile FileInfo
çalışacak kod bunun yerine ile Uri çalışır.
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);
ve dosya sistemi türlerinin Uri
yanı sıra aşağıdaki türler de desteklenir:
bool
byte
DateTime
DateTimeOffset
decimal
double
float
Guid
int
long
sbyte
short
uint
ulong
ushort
Nesneleri kullanma System.CommandLine
Nesneye InvocationContext erişmenizi sağlayan bir SetHandler
aşırı yükleme vardır. Bu nesne daha sonra diğer System.CommandLine
nesnelere erişmek için kullanılabilir. Örneğin, aşağıdaki nesnelere erişiminiz vardır:
InvocationContext
Örnekler için bkz . Çıkış kodlarını ayarlama ve Sonlandırmayı işleme.
CancellationToken
kullanma hakkında CancellationTokenbilgi için bkz . Sonlandırmayı işleme.
IConsole
IConsole test ve birçok genişletilebilirlik senaryolarını kullanmaktan System.Console
daha kolay hale getirir. Özelliğinde InvocationContext.Console kullanılabilir.
ParseResult
ParseResult nesnesi özelliğinde InvocationContext.ParseResult kullanılabilir. Komut satırı girişini ayrıştırma sonuçlarını temsil eden tekil bir yapıdır. Komut satırında seçeneklerin veya bağımsız değişkenlerin olup olmadığını denetlemek veya özelliğini almak ParseResult.UnmatchedTokens için bunu kullanabilirsiniz. Bu özellik ayrıştırılmış ancak yapılandırılmış komut, seçenek veya bağımsız değişkenle eşleşmemiş belirteçlerin listesini içerir.
Eşleşmeyen belirteçlerin listesi, sarmalayıcı gibi davranan komutlarda kullanışlıdır. Sarmalayıcı komutu bir dizi belirteç alır ve bunları başka bir komut veya uygulamaya iletir. sudo
Linux'taki komut bir örnektir. Kimliğine bürünmek için bir kullanıcının adını alır ve ardından çalıştırılacak bir komut alır. Örneğin:
sudo -u admin apt update
Bu komut satırı, apt update
komutunu kullanıcısı admin
olarak çalıştırır.
Bunun gibi bir sarmalayıcı komutu uygulamak için komut özelliğini TreatUnmatchedTokensAsErrors olarak false
ayarlayın. ParseResult.UnmatchedTokens
Ardından özelliği, komutuna açıkça ait olmayan tüm bağımsız değişkenleri içerir. Yukarıdaki örnekte ParseResult.UnmatchedTokens
ve update
belirteçleri yer alırapt
. Komut işleyiciniz daha sonra öğesini yeni bir kabuk çağrısına iletebilir UnmatchedTokens
, örneğin.
Özel doğrulama ve bağlama
Özel doğrulama kodu sağlamak için aşağıdaki örnekte gösterildiği gibi komutunuzda, seçeneğinizde veya bağımsız değişkeninizde çağrısı AddValidator yapın:
var delayOption = new Option<int>("--delay");
delayOption.AddValidator(result =>
{
if (result.GetValueForOption(delayOption) < 1)
{
result.ErrorMessage = "Must be greater than 0";
}
});
Girişi ayrıştırmak ve doğrulamak istiyorsanız, aşağıdaki örnekte gösterildiği gibi bir ParseArgument<T> temsilci kullanın:
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.
}
});
Yukarıdaki kod olarak ayarlır isDefault
true
, böylece parseArgument
kullanıcı bu seçenek için bir değer girmese bile temsilci çağrılır.
ile gerçekleştiremezseniz ParseArgument<T>
yapabileceklerinizle ilgili bazı örnekler aşağıda verilmiştir AddValidator
:
Aşağıdaki örnekteki sınıfı gibi özel türleri ayrıştırma
Person
: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 };
Diğer giriş dizelerinin ayrıştırılması (örneğin, "1,2,3" öğesini içine ayrıştırın
int[]
).Dinamik arity. Örneğin, dize dizileri olarak tanımlanan iki bağımsız değişkeniniz vardır ve komut satırı girişinde bir dizi dizeyi işlemeniz gerekir. yöntemi, ArgumentResult.OnlyTake giriş dizelerini bağımsız değişkenler arasında dinamik olarak bölmenizi sağlar.