Bagikan melalui


Tutorial: Mulai menggunakan System.CommandLine

Penting

System.CommandLine saat ini dalam PRATINJAU, dan dokumentasi ini untuk versi 2.0 beta 5. Beberapa informasi berkaitan dengan produk prarilis yang mungkin dimodifikasi secara substansial sebelum dirilis. Microsoft tidak memberikan jaminan, tersurat maupun tersirat, sehubungan dengan informasi yang diberikan di sini.

Tutorial ini menunjukkan cara membuat aplikasi baris perintah .NET yang menggunakan pustaka System.CommandLine. Anda akan mulai dengan membuat perintah root sederhana yang memiliki satu opsi. Kemudian Anda akan membangun di dasar itu, membuat aplikasi yang lebih kompleks yang berisi beberapa sub-perintah dan opsi yang berbeda untuk setiap perintah.

Dalam tutorial ini, Anda mempelajari cara:

  • Membuat perintah, opsi, dan argumen.
  • Tentukan nilai default untuk opsi.
  • Tetapkan opsi dan argumen ke perintah.
  • Tetapkan opsi secara rekursif ke semua sub perintah di bawah perintah.
  • Bekerja dengan beberapa tingkat subperintah bertingkat.
  • Buat alias untuk perintah dan opsi.
  • Bekerja dengan string, string[], int, bool, FileInfo, dan jenis opsi enum.
  • Membaca nilai opsi dalam kode tindakan perintah.
  • Gunakan kode kustom untuk memilah dan memvalidasi opsi.

Prasyarat

Atau

  • Visual Studio 2022 dengan workload pengembangan aplikasi desktop .NET yang sudah terpasang.

Membuat aplikasi

Buat proyek aplikasi konsol .NET 9 bernama "scl".

  1. Buat folder bernama scl untuk proyek, lalu buka prompt perintah di folder baru.

  2. Jalankan perintah berikut:

    dotnet new console --framework net9.0
    

Pasang paket System.CommandLine

  • Jalankan perintah berikut:

    dotnet add package System.CommandLine --prerelease
    

    Atau, di .NET 10+:

    dotnet package add System.CommandLine --prerelease
    

    Opsi --prerelease diperlukan karena pustaka masih dalam versi beta.

Mengurai argumen

  1. Ganti konten Program.cs dengan kode berikut:

    using System.CommandLine;
    using System.CommandLine.Parsing;
    
    namespace scl;
    
    class Program
    {
        static int Main(string[] args)
        {
            Option<FileInfo> fileOption = new("--file")
            {
                Description = "The file to read and display on the console."
            };
    
            RootCommand rootCommand = new("Sample app for System.CommandLine");
            rootCommand.Options.Add(fileOption);
    
            ParseResult parseResult = rootCommand.Parse(args);
            if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
            {
                ReadFile(parsedFile);
                return 0;
            }
            foreach (ParseError parseError in parseResult.Errors)
            {
                Console.Error.WriteLine(parseError.Message);
            }
            return 1;
        }
    
        static void ReadFile(FileInfo file)
        {
            foreach (string line in File.ReadLines(file.FullName))
            {
                Console.WriteLine(line);
            }
        }
    }
    

Kode sebelumnya:

Option<FileInfo> fileOption = new("--file")
{
    Description = "The file to read and display on the console."
};

RootCommand rootCommand = new("Sample app for System.CommandLine");
rootCommand.Options.Add(fileOption);
  • Mengurai args dan memeriksa apakah ada nilai yang disediakan untuk --file opsi. Jika demikian, memanggil metode ReadFile menggunakan nilai hasil penguraian dan mengembalikan kode keluar 0.
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Jika tidak ada nilai yang disediakan untuk --file, mencetak kesalahan penguraian yang tersedia dan mengembalikan kode keluar 1:
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • Metode membaca ReadFile file yang ditentukan dan menampilkan kontennya di konsol:
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

Menguji aplikasi

Anda dapat menggunakan salah satu cara berikut untuk menguji saat mengembangkan aplikasi baris perintah:

  • Jalankan dotnet build perintah, lalu buka prompt perintah di folder scl/bin/Debug/net9.0 untuk menjalankan executable:

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Gunakan dotnet run dan lalukan nilai opsi ke aplikasi alih-alih ke perintah run dengan menyertakannya setelah --, seperti dalam contoh berikut:

    dotnet run -- --file bin/Debug/net9.0/scl.runtimeconfig.json
    

Tutorial ini mengasumsikan Anda menggunakan opsi pertama dari opsi ini.

Saat Anda menjalankan aplikasi, aplikasi akan menampilkan konten file yang ditentukan oleh opsi --file.

{
  "runtimeOptions": {
    "tfm": "net9.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "9.0.0"
    }
  }
}

Tetapi apa yang terjadi jika Anda memintanya untuk menampilkan bantuan dengan memberikan --help? Tidak ada yang dicetak ke konsol, karena aplikasi belum menangani skenario di mana --file tidak disediakan dan tidak ada kesalahan penguraian.

Mengurai argumen dan memanggil ParseResult

System.CommandLine memungkinkan Anda menentukan tindakan yang dipanggil ketika simbol tertentu (perintah, direktif, atau opsi) berhasil diurai. Tindakan ini adalah delegasi yang mengambil System.CommandLine.ParseResult parameter dan mengembalikan int kode keluar (tindakan asinkron juga tersedia). Kode keluar dikembalikan oleh System.CommandLine.Parsing.ParseResult.Invoke metode dan dapat digunakan untuk menunjukkan apakah perintah berhasil dijalankan atau tidak.

  1. Ganti konten Program.cs dengan kode berikut:

    using System.CommandLine;
    
    namespace scl;
    
    class Program
    {
        static int Main(string[] args)
        {
            Option<FileInfo> fileOption = new("--file")
            {
                Description = "The file to read and display on the console."
            };
    
            RootCommand rootCommand = new("Sample app for System.CommandLine");
            rootCommand.Options.Add(fileOption);
    
            rootCommand.SetAction(parseResult =>
            {
                FileInfo parsedFile = parseResult.GetValue(fileOption);
                ReadFile(parsedFile);
                return 0;
            });
    
            ParseResult parseResult = rootCommand.Parse(args);
            return parseResult.Invoke();
        }
    
        static void ReadFile(FileInfo file)
        {
            foreach (string line in File.ReadLines(file.FullName))
            {
                Console.WriteLine(line);
            }
        }
    }
    

Kode sebelumnya:

  • Menentukan bahwa ReadFile adalah metode yang akan dipanggil ketika perintah root dipanggil:

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • Mengurai args dan memanggil hasilnya:

    ParseResult parseResult = rootCommand.Parse(args);
    return parseResult.Invoke();
    

Saat Anda menjalankan aplikasi, aplikasi akan menampilkan konten file yang ditentukan oleh opsi --file.

Apa yang terjadi jika Anda memintanya untuk menampilkan bantuan dengan memberikan --help?

scl --help

Output berikut akan dicetak:

Description:
  Sample app for System.CommandLine

Usage:
  scl [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information
  --file          The file to read and display on the conso

System.CommandLine.RootCommand secara default menyediakan opsi Bantuan, opsi Versi , dan Sarankan direktif. ParseResult.Invoke metode bertanggung jawab untuk memanggil tindakan simbol yang diurai. Ini bisa menjadi tindakan yang secara eksplisit didefinisikan untuk perintah kami, atau tindakan bantuan yang ditentukan oleh System.CommandLine untuk System.CommandLine.Help.HelpOption. Selain itu, ketika mendeteksi kesalahan penguraian, ia mencetaknya ke kesalahan standar, mencetak bantuan ke output standar dan mengembalikan 1 kode keluar:

scl --invalid bla
Unrecognized command or argument '--invalid'.
Unrecognized command or argument 'bla'.

Menambahkan sub perintah dan opsi

Di bagian ini, Anda:

  • Buat opsi lainnya.
  • Buat sub-perintah.
  • Tetapkan opsi baru pada sub-perintah baru.

Opsi baru akan memungkinkan Anda mengonfigurasi warna teks latar depan dan latar belakang serta kecepatan baca-baca. Fitur-fitur ini akan digunakan untuk membaca kumpulan kutipan yang berasal dari tutorial aplikasi konsol Teleprompter.

  1. Salin file sampleQuotes.txt dari repositori GitHub untuk sampel ini ke direktori proyek Anda. Untuk informasi tentang cara mengunduh file, lihat instruksi di Sampel dan Tutorial.

  2. Buka file proyek dan tambahkan elemen <ItemGroup> tepat sebelum tag </Project> penutup:

    <ItemGroup>
      <Content Include="sampleQuotes.txt">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    Menambahkan markup ini menyebabkan file teks disalin ke folder bin/debug/net9.0 saat Anda membuat aplikasi. Jadi, ketika Anda menjalankan executable di folder tersebut, Anda dapat mengakses file berdasarkan nama tanpa menentukan jalur folder.

  3. Di Program.cs, setelah kode yang membuat opsi --file, buat opsi untuk mengontrol kecepatan baca-baca dan warna teks:

    Option<int> delayOption = new("--delay")
    {
        Description = "Delay between lines, specified as milliseconds per character in a line.",
        DefaultValueFactory = parseResult => 42
    };
    Option<ConsoleColor> fgcolorOption = new("--fgcolor")
    {
        Description = "Foreground color of text displayed on the console.",
        DefaultValueFactory = parseResult => ConsoleColor.White
    };
    Option<bool> lightModeOption = new("--light-mode")
    {
        Description = "Background color of text displayed on the console: default is black, light mode is white."
    };
    
  4. Setelah baris yang membentuk perintah root, hapus kode yang menambahkan opsi --file ke dalamnya. Anda menghapusnya di sini karena Anda akan menambahkannya ke subkomando baru.

  5. Setelah baris yang membuat perintah root, buat sub-perintah read. Tambahkan opsi ke sub perintah ini (dengan menggunakan sintaks penginisialisasi koleksi daripada Options properti), dan tambahkan sub perintah ke perintah akar.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Ganti kode SetAction dengan kode SetAction berikut untuk sub-perintah baru:

    readCommand.SetAction(parseResult => ReadFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(delayOption),
        parseResult.GetValue(fgcolorOption),
        parseResult.GetValue(lightModeOption)));
    

    Anda tidak perlu lagi memanggil SetAction pada perintah root karena perintah root tidak lagi dibutuhkan tindakan. Saat perintah memiliki sub-perintah, Anda biasanya harus menentukan salah satu sub-perintah saat memanggil aplikasi baris perintah.

  7. ReadFile Ganti metode tindakan dengan kode berikut:

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    

Aplikasi sekarang terlihat seperti ini:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "The file to read and display on the console."
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");

        Command readCommand = new("read", "Read and display the file.")
        {
            fileOption,
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        rootCommand.Subcommands.Add(readCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
}

Uji subperintah baru

Sekarang jika Anda mencoba menjalankan aplikasi tanpa menentukan subperintah, Anda mendapatkan pesan kesalahan diikuti dengan pesan bantuan yang menentukan subperintah yang tersedia.

scl --file sampleQuotes.txt
'--file' was not matched. Did you mean one of the following?
--help

Required command was not provided.
Unrecognized command or argument '--file'.
Unrecognized command or argument 'sampleQuotes.txt'.

Description:
  Sample app for System.CommandLine

Usage:
  scl [command] [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information

Commands:
  read  Read and display the file.

Teks bantuan untuk sub-perintah read menunjukkan bahwa empat opsi tersedia. Ini menunjukkan nilai yang valid untuk enum.

scl read -h
Description:
  Read and display the file.

Usage:
  scl read [options]

Options:
  --file <file>                                               The file to read and display on the console.
  --delay <delay>                                             Delay between lines, specified as milliseconds per
                                                              character in a line. [default: 42]
  --fgcolor                                                   Foreground color of text displayed on the console.
  <Black|Blue|Cyan|DarkBlue|DarkCyan|DarkGray|DarkGreen|Dark  [default: White]
  Magenta|DarkRed|DarkYellow|Gray|Green|Magenta|Red|White|Ye
  llow>
  --light-mode                                                Background color of text displayed on the console:
                                                              default is black, light mode is white.
  -?, -h, --help                                              Show help and usage information

Jalankan sub-perintah read hanya menentukan opsi --file, dan Anda mendapatkan nilai default untuk tiga opsi lainnya.

scl read --file sampleQuotes.txt

Penundaan default 42 milidetik per karakter menyebabkan kecepatan baca-baca yang lambat. Anda dapat mempercepatnya dengan mengatur --delay ke angka yang lebih rendah.

scl read --file sampleQuotes.txt --delay 0

Anda dapat menggunakan --fgcolor dan --light-mode untuk mengatur warna teks:

scl read --file sampleQuotes.txt --fgcolor red --light-mode

Berikan nilai yang tidak valid untuk --delay dan Anda mendapatkan pesan kesalahan:

scl read --file sampleQuotes.txt --delay forty-two
Cannot parse argument 'forty-two' for option '--int' as expected type 'System.Int32'.

Berikan nilai yang tidak valid untuk --file dan Anda mendapatkan pengecualian:

scl read --file nofile
Unhandled exception: System.IO.FileNotFoundException: Could not find file 'C:\bin\Debug\net9.0\nofile''.
File name: 'C:\bin\Debug\net9.0\nofile''

Menambahkan sub perintah dan validasi kustom

Bagian ini membuat versi akhir aplikasi. Setelah selesai, aplikasi akan memiliki perintah dan opsi berikut:

  • perintah root dengan opsi rekursif* bernama --file
    • perintah quotes
      • perintah read dengan opsi bernama --delay, --fgcolor, dan --light-mode
      • perintah add dengan argumen bernama quote dan byline
      • perintah delete dengan opsi bernama --search-terms

* Opsi rekursif tersedia untuk perintah yang ditetapkan dan secara rekursif untuk semua sub-perintahnya.

Berikut adalah contoh input baris perintah yang memanggil setiap perintah yang tersedia dengan opsi dan argumennya:

scl quotes read --file sampleQuotes.txt --delay 40 --fgcolor red --light-mode
scl quotes add "Hello world!" "Nancy Davolio"
scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"
  1. Di Program.cs, ganti kode yang membuat opsi --file dengan kode berikut:

    Option<FileInfo> fileOption = new("--file")
    {
        Description = "An option whose argument is parsed as a FileInfo",
        Required = true,
        DefaultValueFactory = result =>
        {
            if (result.Tokens.Count == 0)
            {
                return new FileInfo("sampleQuotes.txt");
    
            }
            string filePath = result.Tokens.Single().Value;
            if (!File.Exists(filePath))
            {
                result.AddError("File does not exist");
                return null;
            }
            else
            {
                return new FileInfo(filePath);
            }
        }
    };
    

    Kode ini menggunakan System.CommandLine.Parsing.ArgumentResult untuk menyediakan penguraian kustom, validasi, dan penanganan kesalahan.

    Tanpa kode ini, file yang hilang dilaporkan dengan pengecualian dan pelacakan tumpukan. Dengan kode ini, hanya pesan kesalahan yang ditentukan yang ditampilkan.

    Kode ini juga menentukan nilai default, itulah sebabnya diatur DefaultValueFactory ke metode penguraian kustom.

  2. Setelah kode yang membuat lightModeOption, tambahkan opsi dan argumen untuk perintah add dan delete:

    Option<string[]> searchTermsOption = new("--search-terms")
    {
        Description = "Strings to search for when deleting entries.",
        Required = true,
        AllowMultipleArgumentsPerToken = true
    };
    Argument<string> quoteArgument = new("quote")
    {
        Description = "Text of quote."
    };
    Argument<string> bylineArgument = new("byline")
    {
        Description = "Byline of quote."
    };
    

    Pengaturan xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken memungkinkan Anda menghilangkan nama opsi --search-terms saat menentukan elemen dalam daftar setelah yang pertama. Ini menjadikan contoh input baris perintah berikut setara:

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Ganti kode yang membuat perintah root dan perintah read dengan kode berikut:

    RootCommand rootCommand = new("Sample app for System.CommandLine");
    fileOption.Recursive = true;
    rootCommand.Options.Add(fileOption);
    
    Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
    rootCommand.Subcommands.Add(quotesCommand);
    
    Command readCommand = new("read", "Read and display the file.")
    {
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    quotesCommand.Subcommands.Add(readCommand);
    
    Command deleteCommand = new("delete", "Delete lines from the file.");
    deleteCommand.Options.Add(searchTermsOption);
    quotesCommand.Subcommands.Add(deleteCommand);
    
    Command addCommand = new("add", "Add an entry to the file.");
    addCommand.Arguments.Add(quoteArgument);
    addCommand.Arguments.Add(bylineArgument);
    addCommand.Aliases.Add("insert");
    quotesCommand.Subcommands.Add(addCommand);
    

    Kode ini membuat perubahan berikut:

    • Menghapus opsi --file dari perintah read.

    • Menambahkan opsi --file sebagai opsi rekursif ke perintah root.

    • Membuat perintah quotes dan menambahkannya ke perintah root.

    • Menambahkan perintah read ke perintah quotes alih-alih ke perintah root.

    • Membuat perintah add dan delete dan menambahkannya ke perintah quotes.

    Hasilnya adalah hierarki perintah berikut:

    • Perintah root
      • quotes
        • read
        • add
        • delete

    Aplikasi sekarang menerapkan pola yang direkomendasikan di mana perintah induk (quotes) menentukan area atau grup, dan perintah turunannya (read, add, delete) adalah tindakan.

    Opsi rekursif diterapkan ke perintah dan secara rekursif ke sub-perintah. Karena --file ada di perintah root, perintah tersebut akan tersedia secara otomatis di semua sub-perintah aplikasi.

  4. Setelah kode SetAction, tambahkan kode SetAction baru untuk sub-perintah baru:

    deleteCommand.SetAction(parseResult => DeleteFromFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(searchTermsOption)));
    
    addCommand.SetAction(parseResult => AddToFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(quoteArgument),
        parseResult.GetValue(bylineArgument))
        );
    

    Subperintah quotes tidak memiliki fungsi karena bukan merupakan perintah akhir dalam hierarki. Sub perintah read, add, dan delete adalah perintah akhir di bawah quotes, dan SetAction dipanggil untuk masing-masing.

  5. Tambahkan tindakan untuk add dan delete.

    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
    
        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");
    
        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
    

Aplikasi yang sudah selesai terlihat seperti ini:

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "An option whose argument is parsed as a FileInfo",
            Required = true,
            DefaultValueFactory = result =>
            {
                if (result.Tokens.Count == 0)
                {
                    return new FileInfo("sampleQuotes.txt");

                }
                string filePath = result.Tokens.Single().Value;
                if (!File.Exists(filePath))
                {
                    result.AddError("File does not exist");
                    return null;
                }
                else
                {
                    return new FileInfo(filePath);
                }
            }
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        Option<string[]> searchTermsOption = new("--search-terms")
        {
            Description = "Strings to search for when deleting entries.",
            Required = true,
            AllowMultipleArgumentsPerToken = true
        };
        Argument<string> quoteArgument = new("quote")
        {
            Description = "Text of quote."
        };
        Argument<string> bylineArgument = new("byline")
        {
            Description = "Byline of quote."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        fileOption.Recursive = true;
        rootCommand.Options.Add(fileOption);

        Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
        rootCommand.Subcommands.Add(quotesCommand);

        Command readCommand = new("read", "Read and display the file.")
        {
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        quotesCommand.Subcommands.Add(readCommand);

        Command deleteCommand = new("delete", "Delete lines from the file.");
        deleteCommand.Options.Add(searchTermsOption);
        quotesCommand.Subcommands.Add(deleteCommand);

        Command addCommand = new("add", "Add an entry to the file.");
        addCommand.Arguments.Add(quoteArgument);
        addCommand.Arguments.Add(bylineArgument);
        addCommand.Aliases.Add("insert");
        quotesCommand.Subcommands.Add(addCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        deleteCommand.SetAction(parseResult => DeleteFromFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(searchTermsOption)));

        addCommand.SetAction(parseResult => AddToFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(quoteArgument),
            parseResult.GetValue(bylineArgument))
            );

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");

        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");

        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
}

Bangun proyek, lalu coba perintah berikut.

Kirim file yang tidak eksis ke --file dengan perintah read, dan Anda mendapatkan pesan kesalahan, bukan pengecualian dan pelacakan tumpukan.

scl quotes read --file nofile
File does not exist

Cobalah menjalankan subkomando quotes, dan Anda akan mendapatkan pesan yang meminta Anda untuk menggunakan read, add, atau delete.

scl quotes
Required command was not provided.

Description:
  Work with a file that contains quotes.

Usage:
  scl quotes [command] [options]

Options:
  --file <file>   An option whose argument is parsed as a FileInfo [default: sampleQuotes.txt]
  -?, -h, --help  Show help and usage information

Commands:
  read                          Read and display the file.
  delete                        Delete lines from the file.
  add, insert <quote> <byline>  Add an entry to the file.

Jalankan sub-perintah add, lalu lihat akhir file teks untuk melihat teks yang ditambahkan:

scl quotes add "Hello world!" "Nancy Davolio"

Jalankan subperintah delete dengan string pencarian dari awal file, lalu lihat bagian awal file teks untuk melihat di mana teks dihapus:

scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"

Nota

Jika Anda menjalankan di folder bin/debug/net9.0, di sanalah Anda akan menemukan file dengan perubahan dari perintah add dan delete. Salinan file dalam folder proyek tetap tidak berubah.

Langkah berikutnya

Dalam tutorial ini, Anda membuat aplikasi baris perintah sederhana yang menggunakan System.CommandLine. Untuk mempelajari selengkapnya tentang pustaka, lihat gambaran umum System.CommandLine.