Использование CommandLineParser с Autofac: как бороться с NotParsed <T>? - PullRequest
0 голосов
/ 01 июня 2019

Я пытаюсь использовать Autofac с CommandLineParser , но я наткнулся на камень преткновения, как регистрировать и разрешать разные вещи, как в случае успеха, так и в случае неудачи.Основная проблема, с которой я сталкиваюсь, заключается в том, что Parser.ParseArguments<T>() вернет объект, базовый (абстрактный) класс которого равен ParserResult<T>.Если командная строка успешно проанализирована, объект является Parsed<T>, но если синтаксический анализ завершается неудачно, это NotParsed<T>.

Мне нужна помощь, чтобы зарегистрировать это в Autofac.Это моя текущая попытка:

builder.Register(c => c.Resolve<ParserResult<Options>>() as Parsed<Options>)
       .As<Parsed<Options>>();

builder.Register(c => c.Resolve<ParserResult<Options>>() as NotParsed<Options>)
       .As<NotParsed<Options>>();
:
if (scope.TryResolve<NotParsed<Options>>(out NotParsed<Options> errors))
    return -1;

var worker = scope.Resolve<IWorker>();

Проблема в том, что если я запустил свою программу так, что синтаксический анализ завершится успешно, то TryResolve<NotParsed<T>>(), приведенный выше, выдаст DependencyResolutionException, так как «зарегистрирован делегат для создания экземпляров».из ... вернул ноль. "Это точно, потому что конкретный класс - Parsed<T>, и поэтому as NotParsed<T> вернет ноль.

Вот мой полный код:

using System;
using Autofac;
using CommandLine;

namespace AutofacCommandLineParser
{
    interface IOptions
    {
    }

    interface IWorker
    {
        int Run();
    }

    class Options : IOptions
    {
    }

    class Worker : IWorker
    {
        IOptions _options;

        public Worker(IOptions options) => _options = options;

        public int Run()
        {
            Console.WriteLine("It works!");
            return 0;
        }
    }

    class Program
    {
        static int Main(string[] args)
        {
            var builder = new ContainerBuilder();

            builder.Register(c => new Parser(settings =>
                                             {
                                                 settings.EnableDashDash = true;
                                                 settings.HelpWriter = Console.Error;
                                             }))
                   .As<Parser>()
                   .SingleInstance();

            builder.Register(c => c.Resolve<Parser>().ParseArguments<Options>(args))
                   .As<ParserResult<Options>>()
                   .SingleInstance();

            builder.Register(c => c.Resolve<ParserResult<Options>>() as Parsed<Options>)
                   .As<Parsed<Options>>();

            builder.Register(c => c.Resolve<ParserResult<Options>>() as NotParsed<Options>)
                   .As<NotParsed<Options>>();

            builder.Register(c => c.Resolve<Parsed<Options>>().Value)
                   .As<IOptions>();

            builder.RegisterType<Worker>().As<IWorker>();

            var container = builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                if (scope.TryResolve<NotParsed<Options>>(out NotParsed<Options> errors))
                    return -1;

                var worker = scope.Resolve<IWorker>();
                return worker.Run();
            }
        }
    }
}

Я надеюсь, что не нужно менятьмой код примерно такой:

IWorker worker = null;
try
{
    worker = scope.Resolve<IWorker>();
}

catch (Autofac.Core.DependencyResolutionException ex)
{
    if (scope.Resolve<NotParsed<Options>>() != null)
        return -1;
    throw ex;
}

return worker?.Run() ?? -1;

Обновление: У меня есть кое-что более чистое, но я все еще не доволен необходимостью сделать это:

return scope.Resolve<ParserResult<Options>>() is Parsed<Options>
            ? scope.Resolve<IWorker>().Run()
            : -1;
...