Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Petunjuk / Saran
Artikel ini adalah bagian dari bagian Dasar-Dasar , ditulis untuk pengembang yang mengetahui setidaknya satu bahasa pemrograman dan mempelajari C#. Jika Anda baru dalam pemrograman, mulailah dengan Memulai. Jika Anda memerlukan cakupan pustaka yang komprehensif, lihat dokumentasi pustaka System.CommandLine.
Pustaka System.CommandLine menangani penguraian baris perintah, pembuatan teks bantuan, dan validasi input sehingga Anda dapat fokus pada logika aplikasi Anda. Dalam tutorial ini, Anda membangun CLI pelacak tugas yang menunjukkan konsep inti: perintah, sub perintah, opsi, dan argumen.
Di tutorial ini, Anda akan:
- Buat aplikasi berbasis file dengan menggunakan
System.CommandLinepaket . - Tentukan opsi dan argumen dengan nilai yang di ketik.
- Buat sub perintah dan lampirkan opsi dan argumen ke dalamnya.
- Tangani setiap perintah sub dengan tindakan.
- Uji aplikasi dengan input baris perintah yang berbeda.
Prasyarat
- Instal .NET 10 SDK atau yang lebih baru.
Membuat aplikasi
Mulailah dengan membuat program C# berbasis file dan menambahkan System.CommandLine paket.
Buat file bernama
TaskCli.csdengan konten berikut:#!/usr/bin/env dotnetBaris
#!(shebang) memungkinkan Anda menjalankan file langsung pada sistem Unix. Di Windows, jalankan file dengandotnet run TaskCli.cs.Tambahkan direktif paket
System.CommandLinedanusingpernyataan yang diperlukan.#:package System.CommandLine@2.0.0using System.CommandLine; using System.CommandLine.Parsing; using System.Text.Json;Penting
Versi
2.0.0adalah versi terbaru pada saat penulisan. Periksa halaman NuGet paket untuk versi terbaru untuk memastikan Anda memiliki perbaikan keamanan terbaru.
Memahami struktur perintah
Sebelum menulis kode penguraian apa pun, pertimbangkan seperti apa tampilan CLI dari perspektif pengguna. Pelacak tugas mendukung empat operasi:
dotnet TaskCli.cs -- add "Write documentation" --priority High --due 2026-04-01
dotnet TaskCli.cs -- list --all
dotnet TaskCli.cs -- complete 3
dotnet TaskCli.cs -- remove 3
dotnet TaskCli.cs -- --verbose list
Nota
Setelah --TaskCli.cs dalam contoh sebelumnya menunjukkan kepada dotnet run bahwa semua argumen yang tersisa diteruskan ke aplikasi Anda, daripada ditafsirkan oleh CLI dotnet itu sendiri.
Setiap baris menggunakan beberapa konsep baris perintah:
-
Subperintah adalah kata kerja untuk memberi tahu aplikasi apa yang harus dilakukan. Pelacak tugas memiliki empat:
add, ,list,completedanremove. Setiap sub perintah dapat menentukan parameternya sendiri. -
Argumen adalah nilai posisi yang mengikuti sub-perintah. Dalam
add "Write documentation", string"Write documentation"adalah argumen yang menentukan deskripsi tugas. Dalamcomplete 3, angka3adalah argumen yang menentukan ID tugas. -
Opsi diberi nama nilai yang diawali dengan
--. Dalamadd --priority High --due 2026-04-01, keduanya--prioritydan--duemerupakan opsi dengan nilainya sendiri. Dilist --all,--allopsinya adalah bendera Boolean yang tidak memerlukan nilai. -
Opsi global berlaku untuk setiap sub-perintah. Opsi
--verbosedidefinisikan pada perintah root denganRecursive = true, sehingga berfungsi dengan sub-perintah apa pun. Dalam--verbose list, bendera verbose muncul sebelum sub-perintah, tetapilist --verboseberfungsi dengan sama baiknya.
Di bagian berikut, Anda membangun potongan-potongan ini dari bawah ke atas. Pertama, Anda menentukan opsi individual (seperti --priority dan --all) dan argumen (seperti deskripsi tugas dan ID). Selanjutnya, Anda membuat empat sub-perintah dan melampirkan opsi dan argumen yang relevan ke masing-masing. Kemudian Anda menyambungkan tindakan untuk setiap subperintah. Tindakan adalah kode yang berjalan saat pengguna memanggil perintah tersebut. Terakhir, Anda merakit perintah akar, mengurai input, dan memanggil tindakan yang cocok.
Untuk melihat lebih dalam konsep sintaks baris perintah, lihat Gambaran umum sintaks baris perintah.
Menentukan opsi dan argumen
Opsi mewakili nilai bernama yang ditentukan pengguna dengan -- awalan. Argumen mewakili nilai posisi. Keduanya memiliki tipe data yang kuat.
System.CommandLine mengurai string input ke dalam jenis yang Anda tentukan.
Pustaka System.CommandLine menggunakan jenis generik untuk menjamin keamanan jenis. Saat Anda menulis Option<int>, yang terletak di antara int tanda kurung sudut adalah argumen jenis. Ini beritahu pustaka jenis nilai apa yang dimiliki opsi. Kelas itu sendiri mendeklarasikan parameter tipe (seperti dalam System.CommandLine.Option<T>), dan Anda menyediakan tipe konkret ketika Anda membuat sebuah instans. Pustaka mengurai string input pengguna dan mengonversinya ke jenis tersebut secara otomatis. Jika pengguna menyediakan --delay abcOption<int>, System.CommandLine melaporkan kesalahan penguraian alih-alih meneruskan data buruk ke kode Anda. Anda akan melihat pola ini dengan Option<bool>, , Option<Priority>Option<DateOnly?>, dan System.CommandLine.Argument<T> dalam langkah-langkah berikut. Untuk informasi selengkapnya tentang generik, lihat Generik.
Tentukan opsi. Masing-masing
Option<T>menentukan jenis nilai, nama, dan deskripsi. Opsi--prioritymenggunakanenumjenis, danSystem.CommandLinesecara otomatis memvalidasi input terhadap nilai enum yang valid:var verboseOption = new Option<bool>("--verbose") { Description = "Show detailed output", Recursive = true }; var priorityOption = new Option<Priority>("--priority") { Description = "Task priority level", DefaultValueFactory = _ => Priority.Medium }; var dueOption = new Option<DateOnly?>("--due") { Description = "Due date (uses current culture date format)" }; var allOption = new Option<bool>("--all") { Description = "Include completed tasks" };Recursive = truePengaturan pada--verbosemembuat opsi tersedia di setiap sub-perintah.DefaultValueFactorypada--prioritymenyediakan nilai default sehingga pengguna dapat menghilangkan opsi.Tentukan argumen. Masing-masing
Argument<T>menentukan jenis nilai dan nama:var descriptionArgument = new Argument<string>("description") { Description = "Task description" }; var taskIdArgument = new Argument<int>("id") { Description = "Task ID" };
Perintah build dan sub-perintah
Sebuah System.CommandLine.Command merupakan tindakan yang dapat diaktifkan oleh pengguna. Tambahkan opsi dan argumen yang relevan ke setiap perintah sehingga System.CommandLine mengetahui parameter mana yang termasuk di mana.
Buat empat sub-perintah. Setiap perintah mendapatkan kombinasi opsi dan argumennya sendiri:
var addCommand = new Command("add", "Add a new task") { Arguments = { descriptionArgument }, Options = { priorityOption, dueOption } };var listCommand = new Command("list", "List all tasks") { Options = { allOption } };var completeCommand = new Command("complete", "Mark a task as complete") { Arguments = { taskIdArgument } };var removeCommand = new Command("remove", "Remove a task") { Arguments = { taskIdArgument } };Merakit perintah root. System.CommandLine.RootCommand adalah titik masuk untuk CLI. Tambahkan opsi global
--verbosedan semua sub-perintah:var rootCommand = new RootCommand("A simple task tracker CLI") { Options = { verboseOption }, Subcommands = { addCommand, listCommand, completeCommand, removeCommand } };Teks bantuan yang dibuat secara otomatis menunjukkan deskripsi perintah akar saat pengguna menjalankan
TaskCli --help.
Mengelola perintah dengan tindakan
Setiap subperindakan memerlukan tindakan. Tindakan adalah delegat yang berjalan saat pengguna memanggil perintah tersebut. Delegasi adalah jenis yang mewakili referensi ke metode. Di sini, Anda meneruskan ekspresi lambda (fungsi anonim sebaris yang didefinisikan dengan =>) sebagai delegate. Panggil SetAction untuk menetapkan setiap tindakan. Delegasi menerima ParseResult yang menyediakan akses ke nilai yang diurai melalui GetValue.
Atur tindakan untuk perintah
add. Tindakan ini memperkenalkan interpolasi string ($"..."string yang menyematkan ekspresi dalam kurung kurawal), operator kondisional (?:), dan pola pengujian jenis (due is DateOnly dueDate) yang memeriksa apakah nilai nullable memiliki nilai dan menetapkannya ke variabel baru dalam satu langkah:addCommand.SetAction(parseResult => { var description = parseResult.GetValue(descriptionArgument)!; var priority = parseResult.GetValue(priorityOption); var due = parseResult.GetValue(dueOption); var verbose = parseResult.GetValue(verboseOption); var tasks = LoadTasks(); var id = tasks.Count > 0 ? tasks.Max(t => t.Id) + 1 : 1; var task = new TaskItem(id, description, priority, due, false); tasks.Add(task); SaveTasks(tasks); Console.WriteLine($"Added task {id}: {description}"); if (verbose) { Console.WriteLine($" Priority: {priority}"); if (due is DateOnly dueDate) { Console.WriteLine($" Due: {dueDate}"); } } });Atur tindakan untuk
listperintah . LINQ (Kueri Terintegrasi Bahasa) memberi Anda operator kueri standar untuk koleksi dalam memori. Dalam tindakan ini, Enumerable.Where memfilter tugas hanya ke item yang cocok dengan kondisi, dan Enumerable.ToList mewujudkan urutan yang difilter ke dalam daftar. Aksi tersebut kemudian menggunakanforeachperulangan untuk mengiterasi hasil, dan operator bersyarat untuk memilih simbol status:listCommand.SetAction(parseResult => { var showAll = parseResult.GetValue(allOption); var verbose = parseResult.GetValue(verboseOption); var tasks = LoadTasks(); var filtered = showAll ? tasks : tasks.Where(t => !t.IsComplete).ToList(); if (filtered.Count == 0) { Console.WriteLine("No tasks found."); return; } foreach (var task in filtered) { var status = task.IsComplete ? "✓" : " "; Console.WriteLine($" [{status}] {task.Id}: {task.Description}"); if (verbose) { Console.WriteLine($" Priority: {task.Priority}"); if (task.Due is DateOnly dueDate) { Console.WriteLine($" Due: {dueDate}"); } } } });Untuk detail selengkapnya, lihat LINQ.
Atur tindakan untuk
completeperintah . Tindakan ini menggunakan LINQ Enumerable.FirstOrDefault untuk menemukan:- Tugas mencocokkan
-
Pola
is nulluntuk memeriksa apakah tugas ada. -
Ekspresi
withuntuk membuat instans rekaman baru dengan menyalin nilai yang ada terlebih dahulu, lalu menerapkan properti yang Anda tetapkan diwithpenginisialisasi (di sini,IsComplete = true). Rekaman tidak dapat diubah secara default, sehingga pola salin dan perbarui ini adalah cara Anda menghasilkan nilai yang dimodifikasi.
Karena tindakan dapat gagal (misalnya, ID tugas tidak ada), tindakan mengembalikan kode kesalahan bilangan bulat yang menjadi kode keluar aplikasi:
completeCommand.SetAction(parseResult => { var id = parseResult.GetValue(taskIdArgument); var verbose = parseResult.GetValue(verboseOption); var tasks = LoadTasks(); var task = tasks.FirstOrDefault(t => t.Id == id); if (task is null) { Console.Error.WriteLine($"Task {id} not found."); return -1; } tasks[tasks.IndexOf(task)] = task with { IsComplete = true }; SaveTasks(tasks); Console.WriteLine($"Completed task {id}: {task.Description}"); if (verbose) { Console.WriteLine($" Priority: {task.Priority}"); } return 0; });Atur tindakan untuk
removeperintah . Tindakan ini mengikuti pola pencarian dan validasi yang sama dengancomplete. GunakanFirstOrDefaultuntuk menemukan tugas danis nulluntuk menangani kasus yang hilang:removeCommand.SetAction(parseResult => { var id = parseResult.GetValue(taskIdArgument); var verbose = parseResult.GetValue(verboseOption); var tasks = LoadTasks(); var task = tasks.FirstOrDefault(t => t.Id == id); if (task is null) { Console.Error.WriteLine($"Task {id} not found."); return -1; } tasks.Remove(task); SaveTasks(tasks); Console.WriteLine($"Removed task {id}: {task.Description}"); if (verbose) { Console.WriteLine($" Priority: {task.Priority}"); } return 0; });Uraikan baris perintah dan panggil tindakan yang cocok:
return rootCommand.Parse(args).Invoke();rootCommand.Parse(args)menguraikan input ke dalam ParseResult, dan.Invoke()menjalankan tindakan untuk perintah yang cocok. Nilai yang dikembalikan adalah kode keluar (0 untuk keberhasilan).
Menambahkan jenis pendukung dan pembantu data
Aplikasi ini membutuhkan beberapa bagian pendukung: fungsi lokal, enum, , recorddan konteks serialisasi. Bagian berikut memperkenalkan setiap konsep, menjelaskan mengapa Anda memilihnya, dan menampilkan kode. Aplikasi ini menggunakan System.Text.Json untuk menyimpan tugas sebagai JSON (JavaScript Object Notation). Aplikasi berbasis file mengharuskan deklarasi jenis muncul setelah semua pernyataan tingkat atas dan fungsi lokal.
Tambahkan fungsi lokal yang memuat dan menyimpan tugas. Fungsi lokal adalah metode yang dideklarasikan di dalam fungsi lain, termasuk di dalam fungsi lokal lainnya. Fungsi lokal menjaga logika pembantu tetap dekat dengan kode yang memanggilnya, yang meningkatkan keterbacaan karena pembaca tidak perlu melompat ke kelas atau file terpisah untuk memahami alur. Di sini,
LoadTasksdanSaveTasksmerangkum I/O file yang dibagikan beberapa tindakan perintah, sehingga aplikasi menulis logika muat/simpan sekali dan menggunakannya kembali:static string GetTaskFilePath() => Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "taskcli-sample", "tasks.json"); static List<TaskItem> LoadTasks() { var path = GetTaskFilePath(); if (!File.Exists(path)) { return []; } var json = File.ReadAllText(path); return JsonSerializer.Deserialize(json, TaskJsonContext.Default.ListTaskItem) ?? []; } static void SaveTasks(List<TaskItem> tasks) { var path = GetTaskFilePath(); Directory.CreateDirectory(Path.GetDirectoryName(path)!); var json = JsonSerializer.Serialize(tasks, TaskJsonContext.Default.ListTaskItem); File.WriteAllText(path, json); }Tambahkan enum
Prioritydan rekorTaskItemdi akhir file.public enum Priority { Low, Medium, High }enumadalah jenis nilai yang menentukan sekumpulan konstanta bernama tetap yang didukung oleh jenis integral. Anda dapat mewakili tingkat prioritas dengan bilangan bulat biasa (0, 1, 2), tetapi merupakan pilihan yangenumlebih baik karena beberapa alasan: pengompilasi membatasi penugasan ke nama yang ditentukan, sehingga kesalahan ketik sepertiHihgmenyebabkan kesalahan waktu kompilasi alih-alih bug senyap; namaLow,Medium, danHighmembuat kode lebih mudah dibaca; danSystem.CommandLinesecara otomatis memvalidasi input pengguna terhadap anggota enum, jadi Anda mendapatkan pemeriksaan input gratis.public record TaskItem(int Id, string Description, Priority Priority, DateOnly? Due, bool IsComplete);recordadalah jenis yang dilengkapi kompilator dengan kesetaraan berbasis nilai dan mutasi nondestruktif.recordadalah pilihan yang tepat untukTaskItemkarena data tugas dalam keadaan sederhana tanpa perilaku kompleks—Anda membandingkan tugas berdasarkan nilainya, bukan berdasarkan identitas referensinya. Pengompilasi menghasilkan dukungan ekspresiEquals,GetHashCode,ToString, danwithdari parameter konstruktor, sehingga Anda mendapatkan pemeriksaan kesetaraan yang tepat, tampilan debugging yang mudah, dan pembaruan tak berubah tanpa harus menulis kode yang berulang. Karena rekaman tidak dapat diubah secara default, Anda menggunakan ekspresiwithuntuk menghasilkan salinan yang dimodifikasi (seperti aksicomplete) daripada memodifikasi yang asli, yang mencegah efek samping tidak sengaja saat aksi yang berbeda membaca dan menulis pada daftar yang sama.Tambahkan konteks serialisasi JSON untuk serialisasi yang kompatibel dengan AOT:
[System.Text.Json.Serialization.JsonSourceGenerationOptions(WriteIndented = true)] [System.Text.Json.Serialization.JsonSerializable(typeof(List<TaskItem>))] internal partial class TaskJsonContext : System.Text.Json.Serialization.JsonSerializerContext;Kelas ini menggunakan dua atribut (anotasi metadata yang ditempatkan dalam kurung siku di atas deklarasi). Atribut
[JsonSourceGenerationOptions(WriteIndented = true)]memberi tahu generator sumber untuk memancarkan JSON yang terindentasi untuk keterbacaan. Atribut[JsonSerializable(typeof(List<TaskItem>))]memberi tahu generator jenis mana yang akan dibuat kode serialisasinya. Bersama-sama, atribut ini memungkinkan serialisasi yang dihasilkan sumber, yang menghindari refleksi run-time dan mendukung kompilasi ahead-of-time (AOT).
Uji aplikasi
Jalankan aplikasi dengan input yang berbeda untuk menjalankan setiap sub-perintah.
Lihat bantuan yang dibuat secara otomatis:
dotnet run TaskCli.cs -- --helpDescription: A simple task tracker CLI Usage: TaskCli [command] [options] Options: --verbose Show detailed output -?, -h, --help Show help and usage information --version Show version information Commands: add <description> Add a new task list List all tasks complete <id> Mark a task as complete remove <id> Remove a taskTambahkan tugas dengan opsi yang berbeda:
dotnet run TaskCli.cs -- add "Write documentation" --priority High --due 2026-04-01 dotnet run TaskCli.cs -- add "Review pull request" dotnet run TaskCli.cs -- add "Fix build errors"Added task 1: Write documentation Added task 2: Review pull request Added task 3: Fix build errorsCantumkan tugas dan gunakan
--verboseuntuk menampilkan detail tambahan:dotnet run TaskCli.cs -- --verbose list[ ] 1: Write documentation Priority: High Due: 4/1/2026 [ ] 2: Review pull request Priority: Medium [ ] 3: Fix build errors Priority: MediumSelesaikan tugas, lalu verifikasi daftar filter tugas yang diselesaikan secara default:
dotnet run TaskCli.cs -- complete 2 dotnet run TaskCli.cs -- listCompleted task 2: Review pull request [ ] 1: Write documentation [ ] 3: Fix build errorsGunakan
--alluntuk menyertakan tugas yang telah selesai:dotnet run TaskCli.cs -- list --all[ ] 1: Write documentation [✓] 2: Review pull request [ ] 3: Fix build errorsHapus tugas:
dotnet run TaskCli.cs -- remove 3Removed task 3: Fix build errors
Membersihkan sumber daya
Pelacak tugas menyimpan data dalam file JSON di bawah folder data aplikasi lokal Anda.
taskcli-sample Hapus folder untuk menghapus data sampel:
-
Windows: Hapus
%LOCALAPPDATA%\taskcli-sample. -
macOS: Hapus
~/Library/Application Support/taskcli-sample. -
Linux: Hapus
~/.local/share/taskcli-sample.