共用方式為


如何在 System.CommandLine 中設定相依性插入

重要

System.CommandLine 目前為預覽版,而此文件適用於版本 2.0 搶鮮版 (Beta) 4。 部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

使用自訂繫結器可將自訂類型插入命令處理常式。

因為下列原因,建議您使用處理常式專用的相依性插入 (DI):

  • 命令列應用程式通常為短期處理序,也就是說,啟動成本對效能可能會產生明顯的影響。 必須要計算「按下 Tab 鍵以完成」時,將效能最佳化特別重要。 命令列應用程式與 Web 和 GUI 應用程式不同,這些應用程式通常相對來說,是長時間執行的處理序。 非必要的啟動時間,不適合用於短期的處理序。
  • 執行有多個子命令的命令列應用程式時,只會執行其中一個子命令。 如果應用程式為沒有執行的子命令設定了相依性,不必然會降低效能。

若要設定 DI,請建立衍生自 BinderBase<T> 的類別,其中的 T 是要插入執行個體的介面。 在 GetBoundValue 方法覆寫中,會取得並傳回想要插入的執行個體。 下列範例會為 ILogger 插入預設記錄器實作:

public class MyCustomBinder : BinderBase<ILogger>
{
    protected override ILogger GetBoundValue(
        BindingContext bindingContext) => GetLogger(bindingContext);

    ILogger GetLogger(BindingContext bindingContext)
    {
        using ILoggerFactory loggerFactory = LoggerFactory.Create(
            builder => builder.AddConsole());
        ILogger logger = loggerFactory.CreateLogger("LoggerCategory");
        return logger;
    }
}

呼叫 SetHandler 方法時,將插入類別的執行個體傳遞到 Lambda,並傳遞服務清單中的繫結器類別執行個體:

rootCommand.SetHandler(async (fileOptionValue, logger) =>
    {
        await DoRootCommand(fileOptionValue!, logger);
    },
    fileOption, new MyCustomBinder());

下列程式碼是包含上述範例的完整程式:

using System.CommandLine;
using System.CommandLine.Binding;
using Microsoft.Extensions.Logging;

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

        var rootCommand = new RootCommand("Dependency Injection sample");
        rootCommand.Add(fileOption);

        rootCommand.SetHandler(async (fileOptionValue, logger) =>
            {
                await DoRootCommand(fileOptionValue!, logger);
            },
            fileOption, new MyCustomBinder());

        await rootCommand.InvokeAsync("--file scl.runtimeconfig.json");
    }

    public static async Task DoRootCommand(FileInfo aFile, ILogger logger)
    {
        Console.WriteLine($"File = {aFile?.FullName}");
        logger.LogCritical("Test message");
        await Task.Delay(1000);
    }

    public class MyCustomBinder : BinderBase<ILogger>
    {
        protected override ILogger GetBoundValue(
            BindingContext bindingContext) => GetLogger(bindingContext);

        ILogger GetLogger(BindingContext bindingContext)
        {
            using ILoggerFactory loggerFactory = LoggerFactory.Create(
                builder => builder.AddConsole());
            ILogger logger = loggerFactory.CreateLogger("LoggerCategory");
            return logger;
        }
    }
}

另請參閱

System.CommandLine 概觀