Я пытаюсь использовать 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;