From 28e9c14de453e67b6fa8672ed8a3996cb3a8646e Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Fri, 12 Feb 2021 00:02:59 +0100 Subject: [PATCH] Register the console lazily in CLI type registrar This should fix a strange bug we're seeing in Cake on macOS. --- .../Injection/Infrastructure/TypeRegistrar.cs | 10 ++++++++++ .../Fakes/FakeTypeRegistrar.cs | 13 +++++++++++++ src/Spectre.Console/Cli/ITypeRegistrar.cs | 7 +++++++ .../Cli/Internal/CommandExecutor.cs | 2 +- .../Internal/Composition/DefaultTypeRegistrar.cs | 16 ++++++++++++++++ 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs b/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs index 0632649..c0e3342 100644 --- a/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs +++ b/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs @@ -27,5 +27,15 @@ namespace Injection { _builder.AddSingleton(service, implementation); } + + public void RegisterLazy(Type service, Func func) + { + if (func is null) + { + throw new ArgumentNullException(nameof(func)); + } + + _builder.AddSingleton(service, (provider) => func()); + } } } diff --git a/src/Spectre.Console.Testing/Fakes/FakeTypeRegistrar.cs b/src/Spectre.Console.Testing/Fakes/FakeTypeRegistrar.cs index 440856b..f04fc57 100644 --- a/src/Spectre.Console.Testing/Fakes/FakeTypeRegistrar.cs +++ b/src/Spectre.Console.Testing/Fakes/FakeTypeRegistrar.cs @@ -37,6 +37,19 @@ namespace Spectre.Console.Testing } } + public void RegisterLazy(Type service, Func factory) + { + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + if (!Instances.ContainsKey(service)) + { + Instances.Add(service, new List { factory() }); + } + } + public ITypeResolver Build() { return _resolver; diff --git a/src/Spectre.Console/Cli/ITypeRegistrar.cs b/src/Spectre.Console/Cli/ITypeRegistrar.cs index 0881027..83b73aa 100644 --- a/src/Spectre.Console/Cli/ITypeRegistrar.cs +++ b/src/Spectre.Console/Cli/ITypeRegistrar.cs @@ -21,6 +21,13 @@ namespace Spectre.Console.Cli /// The implementation. void RegisterInstance(Type service, object implementation); + /// + /// Registers the specified instance lazily. + /// + /// The service. + /// The factory that creates the implementation. + void RegisterLazy(Type service, Func factory); + /// /// Builds the type resolver representing the registrations /// specified in the current instance. diff --git a/src/Spectre.Console/Cli/Internal/CommandExecutor.cs b/src/Spectre.Console/Cli/Internal/CommandExecutor.cs index b0a4bb1..3522c36 100644 --- a/src/Spectre.Console/Cli/Internal/CommandExecutor.cs +++ b/src/Spectre.Console/Cli/Internal/CommandExecutor.cs @@ -24,7 +24,7 @@ namespace Spectre.Console.Cli } _registrar.RegisterInstance(typeof(IConfiguration), configuration); - _registrar.RegisterInstance(typeof(IAnsiConsole), configuration.Settings.Console.GetConsole()); + _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); // Create the command model. var model = CommandModelBuilder.Build(configuration); diff --git a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs index dab76d8..701ba41 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs @@ -35,5 +35,21 @@ namespace Spectre.Console.Cli var registration = new ComponentRegistration(service, new CachingActivator(new InstanceActivator(implementation))); _registry.Enqueue(registry => registry.Register(registration)); } + + public void RegisterLazy(Type service, Func factory) + { + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _registry.Enqueue(registry => + { + var activator = new CachingActivator(new InstanceActivator(factory())); + var registration = new ComponentRegistration(service, activator); + + registry.Register(registration); + }); + } } }