diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index b465a443..39ff5c5e 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -42,13 +42,7 @@ module.exports = { collapsible: true, collapsed: true, items: getIOCSideBar() - }, - { - text: 'Compilation', - collapsible: true, - collapsed: true, - items: getCompilationSideBar() - }, + } ] } @@ -230,37 +224,3 @@ function getIOCSideBar() { ] } -function getCompilationSideBar() { - return [ - { - text: 'Compiling code with AssemblyGenerator', - link: '/guide/compilation/assembly-generator' - }, - { - text: 'Generating code with ISourceWriter', - link: '/guide/compilation/source-writer' - }, - { - text: 'The "Frame" Model', - link: '/guide/compilation/frames/', - children: [ - { - text: 'Working with Variables', - link: '/guide/compilation/frames/variables' - }, - { - text: 'Building custom Frames', - link: '/guide/compilation/frames/frame' - }, - { - text: 'Extension methods for Names in code', - link: '/guide/compilation/frames/extension-methods' - }, - { - text: 'Injected Fields', - link: '/guide/compilation/frames/injected-fields' - }, - ] - } - ] -} diff --git a/src/Lamar.AspNetCoreTests/Lamar.AspNetCoreTests.csproj b/src/Lamar.AspNetCoreTests/Lamar.AspNetCoreTests.csproj index 6808ac48..683a8db6 100644 --- a/src/Lamar.AspNetCoreTests/Lamar.AspNetCoreTests.csproj +++ b/src/Lamar.AspNetCoreTests/Lamar.AspNetCoreTests.csproj @@ -10,6 +10,7 @@ + @@ -26,11 +27,11 @@ - + - + diff --git a/src/Lamar.AspNetCoreTests/integrating_with_HostBuilder.cs b/src/Lamar.AspNetCoreTests/integrating_with_HostBuilder.cs index 4c33e095..00505936 100644 --- a/src/Lamar.AspNetCoreTests/integrating_with_HostBuilder.cs +++ b/src/Lamar.AspNetCoreTests/integrating_with_HostBuilder.cs @@ -3,9 +3,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Baseline; +using JasperFx.Core; using Lamar.Microsoft.DependencyInjection; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; diff --git a/src/Lamar.AspNetCoreTests/integration_with_aspnetcore.cs b/src/Lamar.AspNetCoreTests/integration_with_aspnetcore.cs index 57f06abd..3053a811 100644 --- a/src/Lamar.AspNetCoreTests/integration_with_aspnetcore.cs +++ b/src/Lamar.AspNetCoreTests/integration_with_aspnetcore.cs @@ -6,9 +6,9 @@ using System.Threading; using System.Threading.Tasks; using App.Metrics.AspNetCore; -using Baseline; using IdentityServer4.Models; -using JasperFx.CodeGeneration; +using JasperFx.Core; +using JasperFx.Core.Reflection; using Lamar.IoC.Instances; using Lamar.Microsoft.DependencyInjection; using Microsoft.AspNetCore.Builder; diff --git a/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj b/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj index 1445aa16..aa2ba9fa 100644 --- a/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj +++ b/src/Lamar.Diagnostics/Lamar.Diagnostics.csproj @@ -2,7 +2,7 @@ Adds diagnostic checks to the command line of your Lamar-enabled ASP.Net Core app - 11.1.4 + 12.0.0 Jeremy D. Miller net6.0;net7.0 portable diff --git a/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj b/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj index 52a4dc4d..abaae1f6 100644 --- a/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj +++ b/src/Lamar.Microsoft.DependencyInjection/Lamar.Microsoft.DependencyInjection.csproj @@ -1,7 +1,7 @@  Lamar Adapter for HostBuilder Integration - 11.1.4 + 12.0.0 Jeremy D. Miller net6.0;net7.0 portable diff --git a/src/Lamar.Testing/Examples/SetterExamples.cs b/src/Lamar.Testing/Examples/SetterExamples.cs index 4dadfc49..65e5ad3a 100644 --- a/src/Lamar.Testing/Examples/SetterExamples.cs +++ b/src/Lamar.Testing/Examples/SetterExamples.cs @@ -1,6 +1,6 @@ using System; using System.Reflection; -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; using Lamar.Scanning.Conventions; using Shouldly; using StructureMap.Testing.Widget; diff --git a/src/Lamar.Testing/IoC/Acceptance/custom_registration_convention.cs b/src/Lamar.Testing/IoC/Acceptance/custom_registration_convention.cs index 4810715d..3b020828 100644 --- a/src/Lamar.Testing/IoC/Acceptance/custom_registration_convention.cs +++ b/src/Lamar.Testing/IoC/Acceptance/custom_registration_convention.cs @@ -1,5 +1,5 @@ using System.Linq; -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; using Lamar.Scanning.Conventions; using Microsoft.Extensions.DependencyInjection; using Shouldly; diff --git a/src/Lamar.Testing/IoC/Acceptance/missing_instance_requests.cs b/src/Lamar.Testing/IoC/Acceptance/missing_instance_requests.cs index 158b1c6f..8a865801 100644 --- a/src/Lamar.Testing/IoC/Acceptance/missing_instance_requests.cs +++ b/src/Lamar.Testing/IoC/Acceptance/missing_instance_requests.cs @@ -1,4 +1,5 @@ using JasperFx.CodeGeneration; +using JasperFx.Core.Reflection; using Lamar.IoC; using Shouldly; using StructureMap.Testing.Widget; diff --git a/src/Lamar/AssemblyInfo.cs b/src/Lamar/AssemblyInfo.cs index d046b448..8a17ea72 100644 --- a/src/Lamar/AssemblyInfo.cs +++ b/src/Lamar/AssemblyInfo.cs @@ -3,4 +3,4 @@ [assembly: InternalsVisibleTo("Lamar.Testing")] [assembly: InternalsVisibleTo("Lamar.Diagnostics")] -[assembly:IgnoreAssembly] \ No newline at end of file +[assembly: IgnoreAssembly] \ No newline at end of file diff --git a/src/Lamar/Container.cs b/src/Lamar/Container.cs index e09749e5..649971dd 100644 --- a/src/Lamar/Container.cs +++ b/src/Lamar/Container.cs @@ -5,180 +5,244 @@ using System.Threading.Tasks; using JasperFx.Core.Reflection; using Lamar.IoC; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +#region sample_Container-Declaration + +public class Container : Scope, IContainer, INestedContainer, IServiceScopeFactory, IServiceScope, + ISupportRequiredService + + #endregion + { - #region sample_Container-Declaration - public class Container : Scope, IContainer, INestedContainer, IServiceScopeFactory, IServiceScope, - ISupportRequiredService + private bool _isDisposing; + private Container() + { + } - #endregion + public Container(IServiceCollection services) : base(services) { - private bool _isDisposing; + } - private Container() - { - } + public Container(Action configuration) : this(ServiceRegistry.For(configuration)) + { + } + + private Container(ServiceGraph serviceGraph, Container container) : base(serviceGraph, container) + { + } - public Container(IServiceCollection services) : base(services) + public INestedContainer GetNestedContainer() + { + assertNotDisposed(); + return new Container(ServiceGraph, this); + } + + public override void Dispose() + { + // Because a StackOverflowException when trying to cleanly shut down + // an application is really no fun + if (_isDisposing) { + return; } - public Container(Action configuration) : this(ServiceRegistry.For(configuration)) + _isDisposing = true; + + base.Dispose(); + + if (ReferenceEquals(Root, this)) { + ServiceGraph.Dispose(); } + } - private Container(ServiceGraph serviceGraph, Container container) : base(serviceGraph, container) + public override async ValueTask DisposeAsync() + { + // Because a StackOverflowException when trying to cleanly shut down + // an application is really no fun + if (_isDisposing) { + return; } - public INestedContainer GetNestedContainer() + _isDisposing = true; + + await base.DisposeAsync(); + + if (ReferenceEquals(Root, this)) { - assertNotDisposed(); - return new Container(ServiceGraph, this); + await ServiceGraph.DisposeAsync(); } + } - public override void Dispose() - { - // Because a StackOverflowException when trying to cleanly shut down - // an application is really no fun - if (_isDisposing) return; - _isDisposing = true; + public void AssertConfigurationIsValid(AssertMode mode = AssertMode.Full) + { + using (var writer = new StringWriter()) + { + var hasErrors = validateConfiguration(writer); - base.Dispose(); + if (!hasErrors && mode == AssertMode.Full) + { + hasErrors = buildAndValidateAll(writer); + } - if (ReferenceEquals(Root, this)) ServiceGraph.Dispose(); + if (hasErrors) + { + throw new ContainerValidationException(writer.ToString(), WhatDoIHave(), WhatDidIScan()); + } } + } - public override async ValueTask DisposeAsync() + /// + /// Add additional configurations to this container. NOT RECOMMENDED. + /// + /// + /// + public void Configure(IServiceCollection services) + { + if (services.Any(x => x.ServiceType == typeof(IFamilyPolicy))) { - // Because a StackOverflowException when trying to cleanly shut down - // an application is really no fun - if (_isDisposing) return; - - _isDisposing = true; - - await base.DisposeAsync(); + throw new InvalidOperationException("Cannot register any IFamilyPolicy objects in Configure()"); + } - if (ReferenceEquals(Root, this)) await ServiceGraph.DisposeAsync(); + if (services.Any(x => x.ServiceType == typeof(IFamilyPolicy))) + { + throw new InvalidOperationException("Cannot register any IFamilyPolicy objects in Configure()"); } + ServiceGraph.AppendServices(services); + } - public void AssertConfigurationIsValid(AssertMode mode = AssertMode.Full) + /// + /// Add additional configurations to this container. NOT RECOMMENDED. + /// + /// + public void Configure(Action configure) + { + if (!ReferenceEquals(this, Root)) { - using (var writer = new StringWriter()) - { - var hasErrors = validateConfiguration(writer); + throw new InvalidOperationException("Configure() cannot be used with nested containers"); + } - if (!hasErrors && mode == AssertMode.Full) hasErrors = buildAndValidateAll(writer); + var services = new ServiceRegistry(); + configure(services); - if (hasErrors) - { - throw new ContainerValidationException(writer.ToString(), WhatDoIHave(), WhatDidIScan()); - } - } - } + Configure(services); + } - /// - /// Add additional configurations to this container. NOT RECOMMENDED. - /// - /// - /// - public void Configure(IServiceCollection services) - { - if (services.Any(x => x.ServiceType == typeof(IFamilyPolicy))) - throw new InvalidOperationException("Cannot register any IFamilyPolicy objects in Configure()"); - if (services.Any(x => x.ServiceType == typeof(IFamilyPolicy))) - throw new InvalidOperationException("Cannot register any IFamilyPolicy objects in Configure()"); - ServiceGraph.AppendServices(services); - } + IServiceScope IServiceScopeFactory.CreateScope() + { + return (IServiceScope)GetNestedContainer(); + } - /// - /// Add additional configurations to this container. NOT RECOMMENDED. - /// - /// - public void Configure(Action configure) - { - if (!ReferenceEquals(this, Root)) - throw new InvalidOperationException("Configure() cannot be used with nested containers"); - var services = new ServiceRegistry(); - configure(services); + object ISupportRequiredService.GetRequiredService(Type serviceType) + { + return GetInstance(serviceType); + } - Configure(services); - } + public new static Container Empty() + { + return For(_ => { }); + } + public static Container For() where T : ServiceRegistry, new() + { + return new Container(new T()); + } - IServiceScope IServiceScopeFactory.CreateScope() - { - return (IServiceScope) GetNestedContainer(); - } + public static Container For(Action configuration) + { + var registry = new ServiceRegistry(); + configuration(registry); + return new Container(registry); + } - object ISupportRequiredService.GetRequiredService(Type serviceType) - { - return GetInstance(serviceType); - } + public static Task BuildAsync(Action configure) + { + var services = new ServiceRegistry(); + configure(services); - public new static Container Empty() - { - return For(_ => { }); - } + return BuildAsync(services); + } - public static Container For() where T : ServiceRegistry, new() - { - return new Container(new T()); - } + public static async Task BuildAsync(IServiceCollection services) + { + var container = new Container(); - public static Container For(Action configuration) - { - var registry = new ServiceRegistry(); - configuration(registry); + var graph = await ServiceGraph.BuildAsync(services, container); - return new Container(registry); - } + container.Root = container; + container.ServiceGraph = graph; - public static Task BuildAsync(Action configure) - { - var services = new ServiceRegistry(); - configure(services); + graph.Initialize(); - return BuildAsync(services); - } + return container; + } - public static async Task BuildAsync(IServiceCollection services) - { - var container = new Container(); + private bool buildAndValidateAll(StringWriter writer) + { + var hasErrors = false; - var graph = await ServiceGraph.BuildAsync(services, container); + foreach (var instance in Model.AllInstances.Where(x => + x.Lifetime == ServiceLifetime.Singleton && !x.ServiceType.IsOpenGeneric())) + { + try + { + Debug.WriteLine($"Trying to resolve {instance.ServiceType.FullNameInCode()}"); + var o = instance.Instance.Resolve(this); - container.Root = container; - container.ServiceGraph = graph; - - graph.Initialize(); + if (o != null) + { + foreach (var method in ValidationMethodAttribute.GetValidationMethods(o.GetType())) + { + try + { + method.Invoke(o, new object[0]); + } + catch (Exception e) + { + hasErrors = true; + + writer.WriteLine($"Error in {o.GetType().FullNameInCode()}.{method.Name}()"); + writer.WriteLine(e.ToString()); + writer.WriteLine(); + writer.WriteLine(); + } + } + } + } + catch (Exception e) + { + hasErrors = true; - return container; + writer.WriteLine("Error in " + instance); + writer.WriteLine(e.ToString()); + writer.WriteLine(); + writer.WriteLine(); + } } - private bool buildAndValidateAll(StringWriter writer) + using (var scope = new Scope(ServiceGraph, this)) { - var hasErrors = false; - foreach (var instance in Model.AllInstances.Where(x => - x.Lifetime == ServiceLifetime.Singleton && !x.ServiceType.IsOpenGeneric())) + x.Lifetime != ServiceLifetime.Singleton && !x.ServiceType.IsOpenGeneric())) + { try { - Debug.WriteLine($"Trying to resolve {instance.ServiceType.FullNameInCode()}"); var o = instance.Instance.Resolve(this); if (o != null) + { foreach (var method in ValidationMethodAttribute.GetValidationMethods(o.GetType())) + { try { method.Invoke(o, new object[0]); @@ -192,6 +256,8 @@ private bool buildAndValidateAll(StringWriter writer) writer.WriteLine(); writer.WriteLine(); } + } + } } catch (Exception e) { @@ -202,72 +268,38 @@ private bool buildAndValidateAll(StringWriter writer) writer.WriteLine(); writer.WriteLine(); } - - using (var scope = new Scope(ServiceGraph, this)) - { - foreach (var instance in Model.AllInstances.Where(x => - x.Lifetime != ServiceLifetime.Singleton && !x.ServiceType.IsOpenGeneric())) - try - { - var o = instance.Instance.Resolve(this); - - if (o != null) - foreach (var method in ValidationMethodAttribute.GetValidationMethods(o.GetType())) - try - { - method.Invoke(o, new object[0]); - } - catch (Exception e) - { - hasErrors = true; - - writer.WriteLine($"Error in {o.GetType().FullNameInCode()}.{method.Name}()"); - writer.WriteLine(e.ToString()); - writer.WriteLine(); - writer.WriteLine(); - } - } - catch (Exception e) - { - hasErrors = true; - - writer.WriteLine("Error in " + instance); - writer.WriteLine(e.ToString()); - writer.WriteLine(); - writer.WriteLine(); - } } - - return hasErrors; } - private bool validateConfiguration(StringWriter writer) - { - var invalids = Model.AllInstances.Where(x => x.Instance.ErrorMessages.Any()).ToArray(); + return hasErrors; + } - if (!invalids.Any()) return false; + private bool validateConfiguration(StringWriter writer) + { + var invalids = Model.AllInstances.Where(x => x.Instance.ErrorMessages.Any()).ToArray(); + if (!invalids.Any()) + { + return false; + } - foreach (var instance in invalids) - { - writer.WriteLine(instance); - foreach (var message in instance.Instance.ErrorMessages) writer.WriteLine(message); - writer.WriteLine(); - writer.WriteLine(); - } + foreach (var instance in invalids) + { + writer.WriteLine(instance); + foreach (var message in instance.Instance.ErrorMessages) writer.WriteLine(message); - return true; + writer.WriteLine(); + writer.WriteLine(); } - - + return true; } +} - /// - /// Use internally by Lamar - /// - public interface IStub - { - } +/// +/// Use internally by Lamar +/// +public interface IStub +{ } \ No newline at end of file diff --git a/src/Lamar/DefaultConstructorAttribute.cs b/src/Lamar/DefaultConstructorAttribute.cs index 83b807e8..584e76d2 100644 --- a/src/Lamar/DefaultConstructorAttribute.cs +++ b/src/Lamar/DefaultConstructorAttribute.cs @@ -2,37 +2,36 @@ using System.Linq; using System.Reflection; -namespace Lamar +namespace Lamar; + +/// +/// Used to override the constructor of a class to be used by StructureMap to create +/// a Pluggable object +/// +[AttributeUsage(AttributeTargets.Constructor)] +public class DefaultConstructorAttribute : Attribute { /// - /// Used to override the constructor of a class to be used by StructureMap to create - /// a Pluggable object + /// Examines a System.Type object and determines the ConstructorInfo to use in creating + /// instances of the Type /// - [AttributeUsage(AttributeTargets.Constructor)] - public class DefaultConstructorAttribute : Attribute + /// + /// + public static ConstructorInfo GetConstructor(Type exportedType) { - /// - /// Examines a System.Type object and determines the ConstructorInfo to use in creating - /// instances of the Type - /// - /// - /// - public static ConstructorInfo GetConstructor(Type exportedType) + ConstructorInfo returnValue = null; + + foreach (var constructor in exportedType.GetConstructors()) { - ConstructorInfo returnValue = null; + var atts = constructor.GetCustomAttributes(typeof(DefaultConstructorAttribute), true); - foreach (var constructor in exportedType.GetConstructors()) + if (atts.Any()) { - var atts = constructor.GetCustomAttributes(typeof (DefaultConstructorAttribute), true); - - if (atts.Any()) - { - returnValue = constructor; - break; - } + returnValue = constructor; + break; } - - return returnValue; } + + return returnValue; } } \ No newline at end of file diff --git a/src/Lamar/Diagnostics/IModel.cs b/src/Lamar/Diagnostics/IModel.cs index 1845a2b5..27fba6bd 100644 --- a/src/Lamar/Diagnostics/IModel.cs +++ b/src/Lamar/Diagnostics/IModel.cs @@ -3,100 +3,98 @@ using Lamar.IoC.Instances; using Lamar.Scanning.Conventions; -namespace Lamar.Diagnostics +namespace Lamar.Diagnostics; + +/// +/// Can be used to analyze and query the registrations and configuration +/// of the running Container or Scope +/// +public interface IModel { /// - /// Can be used to analyze and query the registrations and configuration - /// of the running Container or Scope + /// Access to all the Service Type registrations + /// + IEnumerable ServiceTypes { get; } + + /// + /// All explicitly known Instance's in this container. Other instances can be created during + /// the lifetime of the container /// - public interface IModel - { - /// - /// Retrieves the configuration for the given type - /// - /// - /// - IServiceFamilyConfiguration For(); + IEnumerable AllInstances { get; } - /// - /// Retrieves the configuration for the given type - /// - /// - /// - IServiceFamilyConfiguration For(Type type); + /// + /// All of the assembly scanning operations that were used to build this + /// Container + /// + IEnumerable Scanners { get; } - /// - /// Access to all the Service Type registrations - /// - IEnumerable ServiceTypes { get; } + /// + /// Retrieves the configuration for the given type + /// + /// + /// + IServiceFamilyConfiguration For(); - /// - /// Queryable access to all of the Instance for a given ServiceType - /// - /// - /// - IEnumerable InstancesOf(Type serviceType); + /// + /// Retrieves the configuration for the given type + /// + /// + /// + IServiceFamilyConfiguration For(Type type); - /// - /// Queryable access to all of the Instance for a given ServiceType - /// - /// - IEnumerable InstancesOf(); + /// + /// Queryable access to all of the Instance for a given ServiceType + /// + /// + /// + IEnumerable InstancesOf(Type serviceType); - /// - /// Find the concrete type for the default Instance of T. - /// In other words, when I call Container.GetInstance(Type), - /// what do I get? May be indeterminate - /// - /// - /// - Type DefaultTypeFor(); + /// + /// Queryable access to all of the Instance for a given ServiceType + /// + /// + IEnumerable InstancesOf(); - /// - /// Find the concrete type for the default Instance of pluginType. - /// In other words, when I call Container.GetInstance(Type), - /// what do I get? May be indeterminate - /// - /// - Type DefaultTypeFor(Type serviceType); - - /// - /// All explicitly known Instance's in this container. Other instances can be created during - /// the lifetime of the container - /// - IEnumerable AllInstances { get; } + /// + /// Find the concrete type for the default Instance of T. + /// In other words, when I call Container.GetInstance(Type), + /// what do I get? May be indeterminate + /// + /// + /// + Type DefaultTypeFor(); - /// - /// Get each and every configured instance that could possibly - /// be cast to T - /// - /// - /// - T[] GetAllPossible() where T : class; - - /// - /// Can Lamar fulfill a request to ObjectFactory.GetInstance(pluginType) from the - /// current configuration. This does not include concrete classes that could be auto-configured - /// upon demand - /// - /// - /// - bool HasRegistrationFor(Type serviceType); + /// + /// Find the concrete type for the default Instance of pluginType. + /// In other words, when I call Container.GetInstance(Type), + /// what do I get? May be indeterminate + /// + /// + Type DefaultTypeFor(Type serviceType); - /// - /// Can Lamar fulfill a request to ObjectFactory.GetInstance<T>() from the - /// current configuration. This does not include concrete classes that could be auto-configured - /// upon demand - /// - /// - /// - bool HasRegistrationFor(); + /// + /// Get each and every configured instance that could possibly + /// be cast to T + /// + /// + /// + T[] GetAllPossible() where T : class; - /// - /// All of the assembly scanning operations that were used to build this - /// Container - /// - IEnumerable Scanners { get; } + /// + /// Can Lamar fulfill a request to ObjectFactory.GetInstance(pluginType) from the + /// current configuration. This does not include concrete classes that could be auto-configured + /// upon demand + /// + /// + /// + bool HasRegistrationFor(Type serviceType); - } + /// + /// Can Lamar fulfill a request to ObjectFactory.GetInstance<T>() from the + /// current configuration. This does not include concrete classes that could be auto-configured + /// upon demand + /// + /// + /// + bool HasRegistrationFor(); } \ No newline at end of file diff --git a/src/Lamar/Diagnostics/InstanceRef.cs b/src/Lamar/Diagnostics/InstanceRef.cs index 4bd57419..a22f8fc9 100644 --- a/src/Lamar/Diagnostics/InstanceRef.cs +++ b/src/Lamar/Diagnostics/InstanceRef.cs @@ -2,103 +2,100 @@ using JasperFx.Core; using Lamar.IoC; using Lamar.IoC.Instances; -using Lamar.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Diagnostics +namespace Lamar.Diagnostics; + +/// +/// A diagnostic wrapper around registered Instance's +/// +public class InstanceRef { - /// - /// A diagnostic wrapper around registered Instance's - /// - public class InstanceRef - { - private readonly Scope _rootScope; - private readonly Scope _scope; + private readonly Scope _rootScope; + private readonly Scope _scope; - public InstanceRef(Instance instance, Scope scope) - { - Instance = instance; - _scope = scope; - _rootScope = scope.Root; - } + public InstanceRef(Instance instance, Scope scope) + { + Instance = instance; + _scope = scope; + _rootScope = scope.Root; + } - /// - /// The underlying Lamar model for building this configured Instance. ACCESS THIS WITH CAUTION! - /// - public Instance Instance { get; } + /// + /// The underlying Lamar model for building this configured Instance. ACCESS THIS WITH CAUTION! + /// + public Instance Instance { get; } - /// - /// The lifecycle of this specific Instance - /// - public ServiceLifetime Lifetime => Instance.Lifetime; + /// + /// The lifecycle of this specific Instance + /// + public ServiceLifetime Lifetime => Instance.Lifetime; - public string Name => Instance.Name; + public string Name => Instance.Name; - /// - /// The actual concrete type of this Instance. Not every type of IInstance - /// can determine the ConcreteType - /// - public Type ImplementationType => Instance.ImplementationType; + /// + /// The actual concrete type of this Instance. Not every type of IInstance + /// can determine the ConcreteType + /// + public Type ImplementationType => Instance.ImplementationType; + public Type ServiceType => Instance.ServiceType; - public Type ServiceType => Instance.ServiceType; + /// + /// Returns the real object represented by this Instance + /// resolved by the underlying Container + /// + /// + /// + public T Get() where T : class + { + return Resolve() as T; + } - /// - /// Returns the real object represented by this Instance - /// resolved by the underlying Container - /// - /// - /// - public T Get() where T : class + /// + /// Has the object already been created and + /// cached in its Lifetime? Mostly useful + /// for Singleton's + /// + /// + public bool ObjectHasBeenCreated() + { + switch (Lifetime) { - return Resolve() as T; + case ServiceLifetime.Transient: + return false; + case ServiceLifetime.Scoped: + return _scope.Services.TryFind(Instance.Hash, out var _); + case ServiceLifetime.Singleton: + return _scope.Root.Services.TryFind(Instance.Hash, out var _); } - /// - /// Has the object already been created and - /// cached in its Lifetime? Mostly useful - /// for Singleton's - /// - /// - public bool ObjectHasBeenCreated() - { - switch (Lifetime) - { - case ServiceLifetime.Transient: - return false; - case ServiceLifetime.Scoped: - return _scope.Services.TryFind(Instance.Hash, out var _); - case ServiceLifetime.Singleton: - return _scope.Root.Services.TryFind(Instance.Hash, out var _); - } - - return false; - } + return false; + } - /// - /// Creates the textual representation of the 'BuildPlan' - /// for this Instance - /// - /// - public string DescribeBuildPlan() - { - return Instance.GetBuildPlan(_rootScope); - } + /// + /// Creates the textual representation of the 'BuildPlan' + /// for this Instance + /// + /// + public string DescribeBuildPlan() + { + return Instance.GetBuildPlan(_rootScope); + } - /// - /// Builds or resolves an object instance for this registration - /// - /// - public object Resolve() - { - return Instance.Resolve(_scope); - } + /// + /// Builds or resolves an object instance for this registration + /// + /// + public object Resolve() + { + return Instance.Resolve(_scope); + } - public override string ToString() - { - return Instance.ToString(); - } + public override string ToString() + { + return Instance.ToString(); } } \ No newline at end of file diff --git a/src/Lamar/Diagnostics/QueryModel.cs b/src/Lamar/Diagnostics/QueryModel.cs index e52e2914..583c2e0a 100644 --- a/src/Lamar/Diagnostics/QueryModel.cs +++ b/src/Lamar/Diagnostics/QueryModel.cs @@ -4,75 +4,72 @@ using JasperFx.Core.Reflection; using Lamar.IoC; using Lamar.Scanning.Conventions; -using JasperFx.CodeGeneration.Util; -namespace Lamar.Diagnostics -{ - internal class QueryModel : IModel - { - private readonly Scope _scope; - - public QueryModel(Scope scope) - { - _scope = scope; - } +namespace Lamar.Diagnostics; - public IServiceFamilyConfiguration For() - { - return For(typeof(T)); - } +internal class QueryModel : IModel +{ + private readonly Scope _scope; - public IServiceFamilyConfiguration For(Type type) - { - return new ServiceFamilyConfiguration(_scope.ServiceGraph.ResolveFamily(type), _scope); - } + public QueryModel(Scope scope) + { + _scope = scope; + } - public IEnumerable ServiceTypes => - _scope.ServiceGraph.Families.Values.Select(x => new ServiceFamilyConfiguration(x, _scope)); - - public IEnumerable InstancesOf(Type serviceType) - { - return For(serviceType).Instances; - } + public IServiceFamilyConfiguration For() + { + return For(typeof(T)); + } - public IEnumerable InstancesOf() - { - return InstancesOf(typeof(T)); - } + public IServiceFamilyConfiguration For(Type type) + { + return new ServiceFamilyConfiguration(_scope.ServiceGraph.ResolveFamily(type), _scope); + } - public Type DefaultTypeFor() - { - return DefaultTypeFor(typeof(T)); - } + public IEnumerable ServiceTypes => + _scope.ServiceGraph.Families.Values.Select(x => new ServiceFamilyConfiguration(x, _scope)); - public Type DefaultTypeFor(Type serviceType) - { - return _scope.ServiceGraph.FindDefault(serviceType)?.ImplementationType; - } + public IEnumerable InstancesOf(Type serviceType) + { + return For(serviceType).Instances; + } - public IEnumerable AllInstances => _scope.ServiceGraph.AllInstances().Select(x => new InstanceRef(x, _scope)).ToArray(); - public T[] GetAllPossible() where T : class - { - return AllInstances.ToArray() - .Where(x => x.ImplementationType.CanBeCastTo(typeof(T))) - .Select(x => x.Resolve()) - .OfType() - .ToArray(); - } + public IEnumerable InstancesOf() + { + return InstancesOf(typeof(T)); + } - public bool HasRegistrationFor(Type serviceType) - { - return _scope.ServiceGraph.FindDefault(serviceType) != null; - } + public Type DefaultTypeFor() + { + return DefaultTypeFor(typeof(T)); + } - public bool HasRegistrationFor() - { - return _scope.ServiceGraph.FindDefault(typeof(T)) != null; - } + public Type DefaultTypeFor(Type serviceType) + { + return _scope.ServiceGraph.FindDefault(serviceType)?.ImplementationType; + } - public IEnumerable Scanners => _scope.ServiceGraph.Scanners; + public IEnumerable AllInstances => + _scope.ServiceGraph.AllInstances().Select(x => new InstanceRef(x, _scope)).ToArray(); + public T[] GetAllPossible() where T : class + { + return AllInstances.ToArray() + .Where(x => x.ImplementationType.CanBeCastTo(typeof(T))) + .Select(x => x.Resolve()) + .OfType() + .ToArray(); + } + public bool HasRegistrationFor(Type serviceType) + { + return _scope.ServiceGraph.FindDefault(serviceType) != null; + } + public bool HasRegistrationFor() + { + return _scope.ServiceGraph.FindDefault(typeof(T)) != null; } + + public IEnumerable Scanners => _scope.ServiceGraph.Scanners; } \ No newline at end of file diff --git a/src/Lamar/IActivationInterceptor.cs b/src/Lamar/IActivationInterceptor.cs index 23340ec7..c0daa8e5 100644 --- a/src/Lamar/IActivationInterceptor.cs +++ b/src/Lamar/IActivationInterceptor.cs @@ -1,14 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Lamar.IoC; -namespace Lamar +namespace Lamar; + +public interface IActivationInterceptor { - public interface IActivationInterceptor - { - T Intercept(Type serviceType, T instance, IServiceContext scope); - } -} + T Intercept(Type serviceType, T instance, IServiceContext scope); +} \ No newline at end of file diff --git a/src/Lamar/IContainer.cs b/src/Lamar/IContainer.cs index 18a60834..0c3d9820 100644 --- a/src/Lamar/IContainer.cs +++ b/src/Lamar/IContainer.cs @@ -1,98 +1,93 @@ using System; -using System.ComponentModel; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +public interface INestedContainer : IServiceContext, IAsyncDisposable { - public interface INestedContainer : IServiceContext, IAsyncDisposable - { - /// - /// Inject an object into a container at runtime. Used primarily for services like - /// HttpContext that are passed into a nested container - /// - /// Service type to inject. - /// Service instance to inject. - /// When true, replaces any previously injected value for the service type. + /// + /// Inject an object into a container at runtime. Used primarily for services like + /// HttpContext that are passed into a nested container + /// + /// Service type to inject. + /// Service instance to inject. + /// When true, replaces any previously injected value for the service type. + void Inject(Type serviceType, object @object, bool replace); - void Inject( Type serviceType, object @object, bool replace ); + /// + /// Inject an object into a container at runtime. Used primarily for services like + /// HttpContext that are passed into a nested container + /// + /// Service type to inject. + /// Service instance to inject. + /// When true, replaces any previously injected value for the service type. + void Inject(T @object, bool replace); - /// - /// Inject an object into a container at runtime. Used primarily for services like - /// HttpContext that are passed into a nested container - /// - /// Service type to inject. - /// Service instance to inject. - /// When true, replaces any previously injected value for the service type. + /// + /// Inject an object into a container at runtime. Used primarily for services like + /// HttpContext that are passed into a nested container + /// + /// Service type to inject. + /// Service instance to inject. + /// When true, replaces any previously injected value for the service type. + void Inject(T @object); +} - void Inject( T @object, bool replace ); +public interface IContainer : IServiceContext +{ + /// + /// Starts a "Nested" Container for atomic, isolated access. + /// + /// The created nested container. + INestedContainer GetNestedContainer(); - /// - /// Inject an object into a container at runtime. Used primarily for services like - /// HttpContext that are passed into a nested container - /// - /// Service type to inject. - /// Service instance to inject. - /// When true, replaces any previously injected value for the service type. + /// + /// Use with caution! Does a full environment test of the configuration of this container. Will try to create + /// every configured instance and afterward calls any methods marked with + /// . + /// + void AssertConfigurationIsValid(AssertMode mode = AssertMode.Full); - void Inject( T @object ); - } - - public interface IContainer : IServiceContext - { - /// - /// Starts a "Nested" Container for atomic, isolated access. - /// - /// The created nested container. - INestedContainer GetNestedContainer(); + /// + /// Add additional registrations to a running service. USE WITH CAUTION. + /// + /// + void Configure(IServiceCollection services); - /// - /// Use with caution! Does a full environment test of the configuration of this container. Will try to create - /// every configured instance and afterward calls any methods marked with - /// . - /// - void AssertConfigurationIsValid(AssertMode mode = AssertMode.Full); + /// + /// Add additional registrations to a running service. USE WITH CAUTION. + /// + /// + void Configure(Action configure); +} - /// - /// Add additional registrations to a running service. USE WITH CAUTION. - /// - /// - void Configure(IServiceCollection services); +public enum AssertMode +{ + /// + /// Only validate on the known configuration of dependencies without trying to build services + /// + ConfigOnly, - /// - /// Add additional registrations to a running service. USE WITH CAUTION. - /// - /// - void Configure(Action configure); - } + /// + /// Validate configuration, try to build all services, and execute any environment tests + /// + Full +} - public enum AssertMode - { - /// - /// Only validate on the known configuration of dependencies without trying to build services - /// - ConfigOnly, - - /// - /// Validate configuration, try to build all services, and execute any environment tests - /// - Full - } - - public enum DisposalLock - { - /// - /// If a user calls IContainer.Dispose(), ignore the request - /// - Ignore, +public enum DisposalLock +{ + /// + /// If a user calls IContainer.Dispose(), ignore the request + /// + Ignore, - /// - /// Default "just dispose the container" behavior - /// - Unlocked, + /// + /// Default "just dispose the container" behavior + /// + Unlocked, - /// - /// Throws an InvalidOperationException when Dispose() is called - /// - ThrowOnDispose - } + /// + /// Throws an InvalidOperationException when Dispose() is called + /// + ThrowOnDispose } \ No newline at end of file diff --git a/src/Lamar/IDecoratorPolicy.cs b/src/Lamar/IDecoratorPolicy.cs index 025a253c..b6cfb06c 100644 --- a/src/Lamar/IDecoratorPolicy.cs +++ b/src/Lamar/IDecoratorPolicy.cs @@ -2,127 +2,117 @@ using System.Linq; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +/// +/// Custom policy applied at service registration that optionally +/// wraps the original Instance with a decorator +/// +public interface IDecoratorPolicy : ILamarPolicy +{ + bool TryWrap(Instance inner, out Instance wrapped); +} + +internal interface IMaybeIntercepted +{ + bool TryWrap(out Instance wrapped); +} + +internal class MaybeIntercepted : IDecoratorPolicy { - /// - /// Custom policy applied at service registration that optionally - /// wraps the original Instance with a decorator - /// - public interface IDecoratorPolicy : ILamarPolicy + internal static readonly MaybeIntercepted Instance = new(); + + public bool TryWrap(Instance inner, out Instance wrapped) { - bool TryWrap(Instance inner, out Instance wrapped); + if (inner is IMaybeIntercepted i) + { + return i.TryWrap(out wrapped); + } + + wrapped = null; + return false; } +} - internal interface IMaybeIntercepted +[LamarIgnore] +public class DecoratorPolicy : DecoratorPolicy where TDecorator : TService +{ + public DecoratorPolicy() : base(typeof(TService), typeof(TDecorator)) { - bool TryWrap(out Instance wrapped); } +} - internal class MaybeIntercepted : IDecoratorPolicy +[LamarIgnore] +public class DecoratorPolicy : IDecoratorPolicy +{ + private readonly Type _decoratorType; + private readonly Type _serviceType; + + public DecoratorPolicy(Type serviceType, Type decoratorType) { - internal static readonly MaybeIntercepted Instance = new MaybeIntercepted(); - - public bool TryWrap(Instance inner, out Instance wrapped) + if (decoratorType.IsAbstract || decoratorType.IsInterface) { - if (inner is IMaybeIntercepted i) - { - return i.TryWrap(out wrapped); - } - - wrapped = null; - return false; + throw new InvalidOperationException("The decorating type (the 2nd type argument) must be a concrete type"); } - } - [LamarIgnore] - public class DecoratorPolicy : DecoratorPolicy where TDecorator : TService - { - public DecoratorPolicy() : base(typeof(TService), typeof(TDecorator)) + if (serviceType.IsOpenGeneric()) { + if (!decoratorType.IsOpenGeneric() || !GenericsPluginGraph.CanBeCast(serviceType, decoratorType)) + { + throw new InvalidOperationException( + $"{decoratorType.FullNameInCode()} cannot be cast to {serviceType.FullNameInCode()}"); + } } - } - [LamarIgnore] - public class DecoratorPolicy : IDecoratorPolicy - { - private readonly Type _serviceType; - private readonly Type _decoratorType; + _serviceType = serviceType; + _decoratorType = decoratorType; - public DecoratorPolicy(Type serviceType, Type decoratorType) + if (!serviceType.IsOpenGeneric()) { - if (decoratorType.IsAbstract || decoratorType.IsInterface) + var hasCtorArg = decoratorType.GetConstructors().SelectMany(x => x.GetParameters()) + .Any(x => x.ParameterType == serviceType); + + if (!hasCtorArg) { - throw new InvalidOperationException("The decorating type (the 2nd type argument) must be a concrete type"); + throw new InvalidOperationException( + $"There must be a constructor argument for the inner {serviceType.FullNameInCode()} argument"); } + } + } - if (serviceType.IsOpenGeneric()) + public bool TryWrap(Instance instance, out Instance wrapped) + { + if (_serviceType.IsOpenGeneric()) + { + if (instance.ServiceType.Closes(_serviceType)) { - if (!decoratorType.IsOpenGeneric() || !GenericsPluginGraph.CanBeCast(serviceType, decoratorType)) - { - throw new InvalidOperationException($"{decoratorType.FullNameInCode()} cannot be cast to {serviceType.FullNameInCode()}"); - } - } + var args = instance.ServiceType.GetGenericArguments(); + var concreteType = _decoratorType.MakeGenericType(args); - _serviceType = serviceType; - _decoratorType = decoratorType; + var decorator = new ConstructorInstance(instance.ServiceType, concreteType, instance.Lifetime); + decorator.AddInline(instance); - if (!serviceType.IsOpenGeneric()) - { - var hasCtorArg = decoratorType.GetConstructors().SelectMany(x => x.GetParameters()) - .Any(x => x.ParameterType == serviceType); + wrapped = decorator; - if (!hasCtorArg) - { - throw new InvalidOperationException($"There must be a constructor argument for the inner {serviceType.FullNameInCode()} argument"); - } + return true; } + + wrapped = null; + return false; } - public bool TryWrap(Instance instance, out Instance wrapped) + if (instance.ServiceType == _serviceType) { - if (_serviceType.IsOpenGeneric()) - { - if (instance.ServiceType.Closes(_serviceType)) - { - var args = instance.ServiceType.GetGenericArguments(); - var concreteType = _decoratorType.MakeGenericType(args); - - var decorator = new ConstructorInstance(instance.ServiceType, concreteType, instance.Lifetime); - decorator.AddInline(instance); - - wrapped = decorator; - - return true; - } - else - { - wrapped = null; - return false; - } - } - else - { - if (instance.ServiceType == _serviceType) - { - var decorator = new ConstructorInstance(_serviceType, _decoratorType, instance.Lifetime); - decorator.AddInline(instance); - - wrapped = decorator; - - return true; - } - else - { - wrapped = null; - return false; - } - } - - + var decorator = new ConstructorInstance(_serviceType, _decoratorType, instance.Lifetime); + decorator.AddInline(instance); + wrapped = decorator; + + return true; } + + wrapped = null; + return false; } } \ No newline at end of file diff --git a/src/Lamar/IFamilyPolicy.cs b/src/Lamar/IFamilyPolicy.cs index 2b23ef09..20eb1324 100644 --- a/src/Lamar/IFamilyPolicy.cs +++ b/src/Lamar/IFamilyPolicy.cs @@ -1,24 +1,23 @@ using System; -namespace Lamar +namespace Lamar; + +/// +/// Allows Lamar to fill in missing registrations by unknown service types +/// at runtime +/// +[LamarIgnore] + +#region sample_IFamilyPolicy + +public interface IFamilyPolicy : ILamarPolicy { - /// - /// Allows Lamar to fill in missing registrations by unknown service types - /// at runtime + /// Allows you to create missing registrations for an unknown service type + /// at runtime. + /// Return null if this policy does not apply to the given type /// - [LamarIgnore] - #region sample_IFamilyPolicy - public interface IFamilyPolicy : ILamarPolicy - { - /// - /// Allows you to create missing registrations for an unknown service type - /// at runtime. - /// Return null if this policy does not apply to the given type - /// - ServiceFamily Build(Type type, ServiceGraph serviceGraph); - } - #endregion - + ServiceFamily Build(Type type, ServiceGraph serviceGraph); +} -} \ No newline at end of file +#endregion \ No newline at end of file diff --git a/src/Lamar/IInstancePolicy.cs b/src/Lamar/IInstancePolicy.cs index 306d7d55..c37ce3f8 100644 --- a/src/Lamar/IInstancePolicy.cs +++ b/src/Lamar/IInstancePolicy.cs @@ -1,42 +1,42 @@ -using System; -using JasperFx.Core.Reflection; +using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +#region sample_IInstancePolicy + +/// +/// Custom policy on Instance construction that is evaluated +/// as part of creating a "build plan" +/// +public interface IInstancePolicy : ILamarPolicy { - #region sample_IInstancePolicy /// - /// Custom policy on Instance construction that is evaluated - /// as part of creating a "build plan" + /// Apply any conventional changes to the configuration + /// of a single Instance /// - - public interface IInstancePolicy : ILamarPolicy - { - /// - /// Apply any conventional changes to the configuration - /// of a single Instance - /// - /// - void Apply(Instance instance); - } - #endregion + /// + void Apply(Instance instance); +} - #region sample_ConfiguredInstancePolicy - /// - /// Base class for using policies against IConfiguredInstance registrations - /// - public abstract class ConfiguredInstancePolicy : IInstancePolicy +#endregion + +#region sample_ConfiguredInstancePolicy + +/// +/// Base class for using policies against IConfiguredInstance registrations +/// +public abstract class ConfiguredInstancePolicy : IInstancePolicy +{ + public void Apply(Instance instance) { - public void Apply(Instance instance) + if (instance is IConfiguredInstance) { - if (instance is IConfiguredInstance) - { - apply(instance.As()); - } + apply(instance.As()); } - - protected abstract void apply(IConfiguredInstance instance); } - #endregion -} \ No newline at end of file + + protected abstract void apply(IConfiguredInstance instance); +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/ILamarPolicy.cs b/src/Lamar/ILamarPolicy.cs index a0685cd2..621204ed 100644 --- a/src/Lamar/ILamarPolicy.cs +++ b/src/Lamar/ILamarPolicy.cs @@ -1,8 +1,9 @@ -namespace Lamar +namespace Lamar; + +/// +/// Marker interface letting Lamar know that this object applies +/// some kind of policy +/// +public interface ILamarPolicy { - /// - /// Marker interface letting Lamar know that this object applies - /// some kind of policy - /// - public interface ILamarPolicy{} } \ No newline at end of file diff --git a/src/Lamar/IRegistrationPolicy.cs b/src/Lamar/IRegistrationPolicy.cs index 999d5804..d5f93ef3 100644 --- a/src/Lamar/IRegistrationPolicy.cs +++ b/src/Lamar/IRegistrationPolicy.cs @@ -1,13 +1,10 @@ -using Microsoft.Extensions.DependencyInjection; +namespace Lamar; -namespace Lamar +/// +/// Policy that can impact the entire service collection of registrations +/// on container constructions +/// +public interface IRegistrationPolicy : ILamarPolicy { - /// - /// Policy that can impact the entire service collection of registrations - /// on container constructions - /// - public interface IRegistrationPolicy : ILamarPolicy - { - void Apply(ServiceRegistry services); - } + void Apply(ServiceRegistry services); } \ No newline at end of file diff --git a/src/Lamar/IServiceContext.cs b/src/Lamar/IServiceContext.cs index d73e2542..fbf5a858 100644 --- a/src/Lamar/IServiceContext.cs +++ b/src/Lamar/IServiceContext.cs @@ -2,158 +2,168 @@ using System.Collections; using System.Collections.Generic; using System.Reflection; -using Lamar.Diagnostics; using JasperFx.CodeGeneration.Model; +using Lamar.Diagnostics; + +namespace Lamar; -namespace Lamar +public interface IServiceContext : IServiceProvider, IDisposable, IAsyncDisposable { - public interface IServiceContext : IServiceProvider, IDisposable, IAsyncDisposable - { - - /// - /// Provides queryable access to the configured serviceType's and Instances of this Container. - /// - IModel Model { get; } - - /// - /// Creates or finds the default instance of . - /// - /// The type which instance is to be created or found. - /// The default instance of . - T GetInstance(); - - /// - /// Creates or finds the named instance of . - /// - /// The type which instance is to be created or found. - /// The name of the instance. - /// The named instance of . - T GetInstance(string name); - - /// - /// Creates or finds the default instance of . - /// - /// The type which instance is to be created or found. - /// The default instance of . - object GetInstance(Type serviceType); - - /// - /// Creates or finds the named instance of . - /// - /// The type which instance is to be created or found. - /// The name of the instance. - /// The named instance of . - object GetInstance(Type serviceType, string name); - - /// - /// Creates or finds the default instance of . Returns the default value of - /// if it is not known to the container. - /// - /// The type which instance is to be created or found. - /// The default instance of if resolved; the default value of - /// otherwise. - T TryGetInstance(); - - /// - /// Creates or finds the named instance of . Returns the default value of - /// if the named instance is not known to the container. - /// - /// The type which instance is to be created or found. - /// The name of the instance. - /// The named instance of if resolved; the default value of - /// otherwise. - T TryGetInstance(string name); - - /// - /// Creates or finds the default instance of . Returns if - /// is not known to the container. - /// - /// The type which instance is to be created or found. - /// The default instance of if resolved; otherwise. - /// - object TryGetInstance(Type serviceType); - - /// - /// Creates or finds the named instance of . Returns if - /// the named instance is not known to the container. - /// - /// The type which instance is to be created or found. - /// The name of the instance. - /// The named instance of if resolved; otherwise. - /// - object TryGetInstance(Type serviceType, string name); - - /// - /// Suitable for building concrete types that will be resolved only a few times - /// to avoid the cost of having to register or build out a pre-compiled "build plan" - /// internally - /// - /// - /// - T QuickBuild(); - - /// - /// Suitable for building concrete types that will be resolved only a few times - /// to avoid the cost of having to register or build out a pre-compiled "build plan" - /// internally - /// - object QuickBuild(Type objectType); - - /// - /// Suitable for building concrete types that will be resolved only a few times - /// to avoid the cost of having to register or build out a pre-compiled "build plan" - /// internally - /// - /// - /// - IReadOnlyList QuickBuildAll(); - - /// - /// Creates or resolves all registered instances of type . - /// - /// The type which instances are to be created or resolved. - /// All created or resolved instances of type . - IReadOnlyList GetAllInstances(); - - /// - /// Creates or resolves all registered instances of the . - /// - /// The type which instances are to be created or resolved. - /// All created or resolved instances of type . - IEnumerable GetAllInstances(Type serviceType); - - /// - /// Returns a report detailing the complete configuration of all service families and Instances - /// - /// Optional parameter to filter the results down to just this service type. - /// Optional parameter to filter the results down to only service types from this - /// . - /// Optional parameter to filter the results down to only service types from this - /// namespace. - /// Optional parameter to filter the results down to any service type whose name contains - /// this text. - /// The detailed report of the configuration. - string WhatDoIHave(Type serviceType = null, Assembly assembly = null, string @namespace = null, - string typeName = null); - - /// - /// Returns a textual report of all the assembly scanners used to build up this Container - /// - /// - string WhatDidIScan(); - - - IServiceVariableSource CreateServiceVariableSource(); - - /// - /// Returns a report detailing the "build plan" for all the matching types - /// - /// - /// - /// - /// - /// - string HowDoIBuild(Type serviceType = null, Assembly assembly = null, string @namespace = null, - string typeName = null); - } + /// + /// Provides queryable access to the configured serviceType's and Instances of this Container. + /// + IModel Model { get; } + + /// + /// Creates or finds the default instance of . + /// + /// The type which instance is to be created or found. + /// The default instance of . + T GetInstance(); + + /// + /// Creates or finds the named instance of . + /// + /// The type which instance is to be created or found. + /// The name of the instance. + /// The named instance of . + T GetInstance(string name); + + /// + /// Creates or finds the default instance of . + /// + /// The type which instance is to be created or found. + /// The default instance of . + object GetInstance(Type serviceType); + + /// + /// Creates or finds the named instance of . + /// + /// The type which instance is to be created or found. + /// The name of the instance. + /// The named instance of . + object GetInstance(Type serviceType, string name); + + /// + /// Creates or finds the default instance of . Returns the default value of + /// if it is not known to the container. + /// + /// The type which instance is to be created or found. + /// + /// The default instance of if resolved; the default value of + /// otherwise. + /// + T TryGetInstance(); + + /// + /// Creates or finds the named instance of . Returns the default value of + /// if the named instance is not known to the container. + /// + /// The type which instance is to be created or found. + /// The name of the instance. + /// + /// The named instance of if resolved; the default value of + /// otherwise. + /// + T TryGetInstance(string name); + + /// + /// Creates or finds the default instance of . Returns if + /// is not known to the container. + /// + /// The type which instance is to be created or found. + /// + /// The default instance of if resolved; otherwise. + /// + object TryGetInstance(Type serviceType); + + /// + /// Creates or finds the named instance of . Returns if + /// the named instance is not known to the container. + /// + /// The type which instance is to be created or found. + /// The name of the instance. + /// + /// The named instance of if resolved; otherwise. + /// + object TryGetInstance(Type serviceType, string name); + + /// + /// Suitable for building concrete types that will be resolved only a few times + /// to avoid the cost of having to register or build out a pre-compiled "build plan" + /// internally + /// + /// + /// + T QuickBuild(); + + /// + /// Suitable for building concrete types that will be resolved only a few times + /// to avoid the cost of having to register or build out a pre-compiled "build plan" + /// internally + /// + object QuickBuild(Type objectType); + + /// + /// Suitable for building concrete types that will be resolved only a few times + /// to avoid the cost of having to register or build out a pre-compiled "build plan" + /// internally + /// + /// + /// + IReadOnlyList QuickBuildAll(); + + /// + /// Creates or resolves all registered instances of type . + /// + /// The type which instances are to be created or resolved. + /// All created or resolved instances of type . + IReadOnlyList GetAllInstances(); + + /// + /// Creates or resolves all registered instances of the . + /// + /// The type which instances are to be created or resolved. + /// All created or resolved instances of type . + IEnumerable GetAllInstances(Type serviceType); + + /// + /// Returns a report detailing the complete configuration of all service families and Instances + /// + /// Optional parameter to filter the results down to just this service type. + /// + /// Optional parameter to filter the results down to only service types from this + /// . + /// + /// + /// Optional parameter to filter the results down to only service types from this + /// namespace. + /// + /// + /// Optional parameter to filter the results down to any service type whose name contains + /// this text. + /// + /// The detailed report of the configuration. + string WhatDoIHave(Type serviceType = null, Assembly assembly = null, string @namespace = null, + string typeName = null); + + /// + /// Returns a textual report of all the assembly scanners used to build up this Container + /// + /// + string WhatDidIScan(); + + + IServiceVariableSource CreateServiceVariableSource(); + + /// + /// Returns a report detailing the "build plan" for all the matching types + /// + /// + /// + /// + /// + /// + string HowDoIBuild(Type serviceType = null, Assembly assembly = null, string @namespace = null, + string typeName = null); } \ No newline at end of file diff --git a/src/Lamar/IServiceFamilyConfiguration.cs b/src/Lamar/IServiceFamilyConfiguration.cs index 8c39f834..db9b32d8 100644 --- a/src/Lamar/IServiceFamilyConfiguration.cs +++ b/src/Lamar/IServiceFamilyConfiguration.cs @@ -3,34 +3,33 @@ using Lamar.Diagnostics; using Lamar.IoC.Instances; -namespace Lamar +namespace Lamar; + +public interface IServiceFamilyConfiguration { - public interface IServiceFamilyConfiguration - { - /// - /// The service type - /// - Type ServiceType { get; } + /// + /// The service type + /// + Type ServiceType { get; } - /// - /// The "instance" that will be used when Container.GetInstance(ServiceType) is called. - /// See InstanceRef for more information - /// - InstanceRef Default { get; } + /// + /// The "instance" that will be used when Container.GetInstance(ServiceType) is called. + /// See InstanceRef for more information + /// + InstanceRef Default { get; } - /// - /// All of the Instance's registered - /// for this ServiceType - /// - IEnumerable Instances { get; } + /// + /// All of the Instance's registered + /// for this ServiceType + /// + IEnumerable Instances { get; } - /// - /// Simply query to see if there are any implementations registered - /// - /// - bool HasImplementations(); + /// + /// Simply query to see if there are any implementations registered + /// + /// + bool HasImplementations(); - // TODO -- add implementation by name? - } + // TODO -- add implementation by name? } \ No newline at end of file diff --git a/src/Lamar/IgnoreAssemblyAttribute.cs b/src/Lamar/IgnoreAssemblyAttribute.cs index e3207145..b4a4fdcd 100644 --- a/src/Lamar/IgnoreAssemblyAttribute.cs +++ b/src/Lamar/IgnoreAssemblyAttribute.cs @@ -1,10 +1,8 @@ using System; -namespace Lamar -{ - [AttributeUsage(AttributeTargets.Assembly)] - public class IgnoreAssemblyAttribute : Attribute - { +namespace Lamar; - } -} +[AttributeUsage(AttributeTargets.Assembly)] +public class IgnoreAssemblyAttribute : Attribute +{ +} \ No newline at end of file diff --git a/src/Lamar/InstanceNameAttribute.cs b/src/Lamar/InstanceNameAttribute.cs index 72da7db4..2b87d0d4 100644 --- a/src/Lamar/InstanceNameAttribute.cs +++ b/src/Lamar/InstanceNameAttribute.cs @@ -1,23 +1,22 @@ using Lamar.IoC.Instances; -namespace Lamar +namespace Lamar; + +/// +/// Configures the Lamar instance name for resolving +/// services by name +/// +public class InstanceNameAttribute : LamarAttribute { - /// - /// Configures the Lamar instance name for resolving - /// services by name - /// - public class InstanceNameAttribute : LamarAttribute - { - private readonly string _name; + private readonly string _name; - public InstanceNameAttribute(string name) - { - _name = name; - } + public InstanceNameAttribute(string name) + { + _name = name; + } - public override void Alter(Instance instance) - { - instance.Name = _name; - } + public override void Alter(Instance instance) + { + instance.Name = _name; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Activation/ActivatingInstance.cs b/src/Lamar/IoC/Activation/ActivatingInstance.cs index bc8beb9f..7f7ba955 100644 --- a/src/Lamar/IoC/Activation/ActivatingInstance.cs +++ b/src/Lamar/IoC/Activation/ActivatingInstance.cs @@ -3,58 +3,61 @@ using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Activation +namespace Lamar.IoC.Activation; + +internal class ActivatingInstance : LambdaInstance { - internal class ActivatingInstance : LambdaInstance + private readonly Instance _inner; + + public ActivatingInstance(Action action, Instance inner) + : base(inner.ServiceType, buildCreator(action, inner), inner.Lifetime) { - private readonly Instance _inner; + inner.Lifetime = ServiceLifetime.Transient; + _inner = inner; + } - public ActivatingInstance(Action action, Instance inner) - : base(inner.ServiceType, buildCreator(action, inner), inner.Lifetime) - { - inner.Lifetime = ServiceLifetime.Transient; - _inner = inner; - } - - protected override IEnumerable createPlan(ServiceGraph services) - { - _inner.CreatePlan(services); - foreach (var message in _inner.ErrorMessages) - { - ErrorMessages.Add(message); - } - - return base.createPlan(services); - } - - + protected override IEnumerable createPlan(ServiceGraph services) + { + _inner.CreatePlan(services); + foreach (var message in _inner.ErrorMessages) ErrorMessages.Add(message); - internal override string GetBuildPlan(Scope rootScope) - { - return $"User defined interception{Environment.NewLine}{base.GetBuildPlan(rootScope)}"; - } + return base.createPlan(services); + } + + + internal override string GetBuildPlan(Scope rootScope) + { + return $"User defined interception{Environment.NewLine}{base.GetBuildPlan(rootScope)}"; + } - private static Func buildCreator(Action interceptor, Instance inner) + private static Func buildCreator(Action interceptor, Instance inner) + { + switch (inner.Lifetime) { - switch (inner.Lifetime) - { - case ServiceLifetime.Singleton: - return s => + case ServiceLifetime.Singleton: + return s => + { + var raw = inner.QuickResolve(s); + if (raw is TActual a) { - var raw = inner.QuickResolve(s); - if (raw is TActual a) interceptor(s, a); - return (TService) raw; - }; - - default: - - return s => + interceptor(s, a); + } + + return (TService)raw; + }; + + default: + + return s => + { + var raw = inner.Resolve(s); + if (raw is TActual a) { - var raw = inner.Resolve(s); - if (raw is TActual a) interceptor(s, a); - return (TService) raw; - }; - } + interceptor(s, a); + } + + return (TService)raw; + }; } } } \ No newline at end of file diff --git a/src/Lamar/IoC/Activation/ActivationPolicy.cs b/src/Lamar/IoC/Activation/ActivationPolicy.cs index 06821e74..4b9be57c 100644 --- a/src/Lamar/IoC/Activation/ActivationPolicy.cs +++ b/src/Lamar/IoC/Activation/ActivationPolicy.cs @@ -1,44 +1,44 @@ using System; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Activation +namespace Lamar.IoC.Activation; + +internal class ActivationPolicy : IDecoratorPolicy { - internal class ActivationPolicy : IDecoratorPolicy + private readonly Action _action; + + public ActivationPolicy(Action action) { - private readonly Action _action; + _action = action; + } - public ActivationPolicy(Action action) + public bool TryWrap(Instance inner, out Instance wrapped) + { + if (TestInstance(inner)) { - _action = action; - } + wrapped = typeof(ActivatingInstance<,>).CloseAndBuildAs(_action, inner, typeof(T), + inner.ServiceType); - public virtual bool TestInstance(Instance inner) - { - if (inner.ServiceType == typeof(T)) - { - return true; - } + return true; + } - if (inner.ImplementationType == null) return false; + wrapped = null; + return false; + } - return inner.ImplementationType.CanBeCastTo(); + public virtual bool TestInstance(Instance inner) + { + if (inner.ServiceType == typeof(T)) + { + return true; } - public bool TryWrap(Instance inner, out Instance wrapped) + if (inner.ImplementationType == null) { - if (TestInstance(inner)) - { - wrapped = typeof(ActivatingInstance<,>).CloseAndBuildAs(_action, inner, typeof(T), - inner.ServiceType); - - return true; - } - - wrapped = null; return false; } + return inner.ImplementationType.CanBeCastTo(); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Activation/InterceptingInstance.cs b/src/Lamar/IoC/Activation/InterceptingInstance.cs index 1d87c336..a02b3b31 100644 --- a/src/Lamar/IoC/Activation/InterceptingInstance.cs +++ b/src/Lamar/IoC/Activation/InterceptingInstance.cs @@ -1,74 +1,70 @@ using System; using System.Collections.Generic; +using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Activation +namespace Lamar.IoC.Activation; + +internal class InterceptingInstance : LambdaInstance + where TImplementation : TService { - internal class InterceptingInstance : LambdaInstance where TImplementation : TService + private readonly Instance _inner; + + public InterceptingInstance(Func interceptor, Instance inner) + : base(inner.ServiceType, buildCreator(interceptor, inner), inner.Lifetime) { - private readonly Instance _inner; + inner.Lifetime = ServiceLifetime.Transient; + _inner = inner; + } - public InterceptingInstance(Func interceptor, Instance inner) - - : base(inner.ServiceType, buildCreator(interceptor, inner), inner.Lifetime) - { - inner.Lifetime = ServiceLifetime.Transient; - _inner = inner; - } + protected override IEnumerable createPlan(ServiceGraph services) + { + _inner.CreatePlan(services); + foreach (var message in _inner.ErrorMessages) ErrorMessages.Add(message); - protected override IEnumerable createPlan(ServiceGraph services) - { - _inner.CreatePlan(services); - foreach (var message in _inner.ErrorMessages) - { - ErrorMessages.Add(message); - } - - return base.createPlan(services); - } - - + return base.createPlan(services); + } - internal override string GetBuildPlan(Scope rootScope) - { - return $"User defined interception{Environment.NewLine}{base.GetBuildPlan(rootScope)}"; - } - private static Func buildCreator(Func interceptor, Instance inner) + internal override string GetBuildPlan(Scope rootScope) + { + return $"User defined interception{Environment.NewLine}{base.GetBuildPlan(rootScope)}"; + } + + private static Func buildCreator(Func interceptor, + Instance inner) + { + switch (inner.Lifetime) { - switch (inner.Lifetime) - { - case ServiceLifetime.Singleton: - return s => + case ServiceLifetime.Singleton: + return s => + { + var raw = inner.QuickResolve(s); + return raw switch { - var raw = inner.QuickResolve(s); - return raw switch - { - TImplementation inner => interceptor(s.Root, inner), - null => throw new InvalidOperationException( - $"Inner instance {inner} of activator returned null"), - _ => throw new InvalidCastException( - $"Activation interceptor expected type {typeof(TImplementation).FullNameInCode()}, but was {raw.GetType().FullNameInCode()}") - }; + TImplementation inner => interceptor(s.Root, inner), + null => throw new InvalidOperationException( + $"Inner instance {inner} of activator returned null"), + _ => throw new InvalidCastException( + $"Activation interceptor expected type {typeof(TImplementation).FullNameInCode()}, but was {raw.GetType().FullNameInCode()}") }; - - default: + }; + + default: - return s => + return s => + { + var raw = inner.Resolve(s); + return raw switch { - var raw = inner.Resolve(s); - return raw switch - { - TImplementation inner => interceptor(s, inner), - null => throw new InvalidOperationException( - $"Inner instance {inner} of activator returned null"), - _ => throw new InvalidCastException( - $"Activation interceptor expected type {typeof(TImplementation).FullNameInCode()}, but was {raw.GetType().FullNameInCode()}") - }; + TImplementation inner => interceptor(s, inner), + null => throw new InvalidOperationException( + $"Inner instance {inner} of activator returned null"), + _ => throw new InvalidCastException( + $"Activation interceptor expected type {typeof(TImplementation).FullNameInCode()}, but was {raw.GetType().FullNameInCode()}") }; - } + }; } } } \ No newline at end of file diff --git a/src/Lamar/IoC/Activation/InterceptorPolicy.cs b/src/Lamar/IoC/Activation/InterceptorPolicy.cs index 5ba3a30c..f636c372 100644 --- a/src/Lamar/IoC/Activation/InterceptorPolicy.cs +++ b/src/Lamar/IoC/Activation/InterceptorPolicy.cs @@ -1,34 +1,32 @@ using System; using Lamar.IoC.Instances; -namespace Lamar.IoC.Activation +namespace Lamar.IoC.Activation; + +internal class InterceptorPolicy : IDecoratorPolicy { - internal class InterceptorPolicy : IDecoratorPolicy + private readonly Func _interceptor; + + public InterceptorPolicy(Func interceptor) { - private readonly Func _interceptor; + _interceptor = interceptor; + } - public InterceptorPolicy(Func interceptor) + public bool TryWrap(Instance inner, out Instance wrapped) + { + if (TestInstance(inner)) { - _interceptor = interceptor; - } + wrapped = new InterceptingInstance(_interceptor, inner); - public virtual bool TestInstance(Instance inner) - { - return inner.ServiceType == typeof(T); + return true; } - public bool TryWrap(Instance inner, out Instance wrapped) - { - if (TestInstance(inner)) - { - wrapped = new InterceptingInstance(_interceptor, inner); - - return true; - } - - wrapped = null; - return false; - } + wrapped = null; + return false; + } + public virtual bool TestInstance(Instance inner) + { + return inner.ServiceType == typeof(T); } } \ No newline at end of file diff --git a/src/Lamar/IoC/AsyncDisposableWrapper.cs b/src/Lamar/IoC/AsyncDisposableWrapper.cs index 58183dc6..a86380f1 100644 --- a/src/Lamar/IoC/AsyncDisposableWrapper.cs +++ b/src/Lamar/IoC/AsyncDisposableWrapper.cs @@ -1,25 +1,24 @@ using System; using System.Threading.Tasks; -namespace Lamar.IoC +namespace Lamar.IoC; + +internal class AsyncDisposableWrapper : IDisposable, IAsyncDisposable { - internal class AsyncDisposableWrapper : IDisposable, IAsyncDisposable - { - private readonly IAsyncDisposable _inner; + private readonly IAsyncDisposable _inner; - public AsyncDisposableWrapper(IAsyncDisposable inner) - { - _inner = inner; - } + public AsyncDisposableWrapper(IAsyncDisposable inner) + { + _inner = inner; + } - public void Dispose() - { - _inner.DisposeAsync().GetAwaiter().GetResult(); - } + public ValueTask DisposeAsync() + { + return _inner.DisposeAsync(); + } - public ValueTask DisposeAsync() - { - return _inner.DisposeAsync(); - } + public void Dispose() + { + _inner.DisposeAsync().GetAwaiter().GetResult(); } } \ No newline at end of file diff --git a/src/Lamar/IoC/BuildMode.cs b/src/Lamar/IoC/BuildMode.cs index 5478fa50..d47ee94a 100644 --- a/src/Lamar/IoC/BuildMode.cs +++ b/src/Lamar/IoC/BuildMode.cs @@ -1,21 +1,20 @@ -namespace Lamar.IoC +namespace Lamar.IoC; + +public enum BuildMode { - public enum BuildMode - { - /// - /// Build as if it is used within a handler like - /// a Jasper message handler or http handler - /// - Inline, - - /// - /// Build as a dependency of another object - /// - Dependency, - - /// - /// Build as a return value inside of a resolver - /// - Build - } + /// + /// Build as if it is used within a handler like + /// a Jasper message handler or http handler + /// + Inline, + + /// + /// Build as a dependency of another object + /// + Dependency, + + /// + /// Build as a return value inside of a resolver + /// + Build } \ No newline at end of file diff --git a/src/Lamar/IoC/ContainerValidationException.cs b/src/Lamar/IoC/ContainerValidationException.cs index 3449fd57..125c666d 100644 --- a/src/Lamar/IoC/ContainerValidationException.cs +++ b/src/Lamar/IoC/ContainerValidationException.cs @@ -1,24 +1,22 @@ using System; -namespace Lamar.IoC +namespace Lamar.IoC; + +public class ContainerValidationException : Exception { - public class ContainerValidationException : Exception + public ContainerValidationException(string message, string whatDoIHave, string whatDidIScan) : base(message) { - /// - /// A textual report of the container configuration at the point the exception was thrown - /// - public string WhatDoIHave { get; } - - /// - /// A textual report of the container type scanning at the point the exception was thrown - /// - public string WhatDidIScan { get; } + WhatDoIHave = whatDoIHave; + WhatDidIScan = whatDidIScan; + } - public ContainerValidationException(string message, string whatDoIHave, string whatDidIScan) : base(message) - { - WhatDoIHave = whatDoIHave; - WhatDidIScan = whatDidIScan; - } + /// + /// A textual report of the container configuration at the point the exception was thrown + /// + public string WhatDoIHave { get; } - } + /// + /// A textual report of the container type scanning at the point the exception was thrown + /// + public string WhatDidIScan { get; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/CharacterWidth.cs b/src/Lamar/IoC/Diagnostics/CharacterWidth.cs index e578cb5f..0c39a9c5 100644 --- a/src/Lamar/IoC/Diagnostics/CharacterWidth.cs +++ b/src/Lamar/IoC/Diagnostics/CharacterWidth.cs @@ -1,36 +1,30 @@ -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +internal class CharacterWidth { - internal class CharacterWidth - { - private int _width; + internal int Width { get; private set; } - internal int Width + internal static CharacterWidth[] For(int count) + { + var widths = new CharacterWidth[count]; + for (var i = 0; i < widths.Length; i++) { - get { return _width; } + widths[i] = new CharacterWidth(); } - internal static CharacterWidth[] For(int count) - { - var widths = new CharacterWidth[count]; - for (var i = 0; i < widths.Length; i++) - { - widths[i] = new CharacterWidth(); - } - - return widths; - } + return widths; + } - internal void SetWidth(int width) + internal void SetWidth(int width) + { + if (width > Width) { - if (width > _width) - { - _width = width; - } + Width = width; } + } - internal void Add(int add) - { - _width += add; - } + internal void Add(int add) + { + Width += add; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/DividerLine.cs b/src/Lamar/IoC/Diagnostics/DividerLine.cs index 326c92dd..4a9793b9 100644 --- a/src/Lamar/IoC/Diagnostics/DividerLine.cs +++ b/src/Lamar/IoC/Diagnostics/DividerLine.cs @@ -1,31 +1,27 @@ using System.IO; -namespace Lamar.IoC.Diagnostics -{ - internal class DividerLine : Line - { - private readonly char _character; +namespace Lamar.IoC.Diagnostics; - internal DividerLine(char character) - { - _character = character; - } +internal class DividerLine : Line +{ + private readonly char _character; - #region Line Members + internal DividerLine(char character) + { + _character = character; + } - public void OverwriteCounts(CharacterWidth[] widths) - { - // no-op - } + #region Line Members - public void Write(TextWriter writer, CharacterWidth[] widths) - { - foreach (var width in widths) - { - writer.Write(string.Empty.PadRight(width.Width, _character)); - } - } + public void OverwriteCounts(CharacterWidth[] widths) + { + // no-op + } - #endregion + public void Write(TextWriter writer, CharacterWidth[] widths) + { + foreach (var width in widths) writer.Write(string.Empty.PadRight(width.Width, _character)); } + + #endregion } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/Line.cs b/src/Lamar/IoC/Diagnostics/Line.cs index 7a080464..8a97cd6b 100644 --- a/src/Lamar/IoC/Diagnostics/Line.cs +++ b/src/Lamar/IoC/Diagnostics/Line.cs @@ -1,10 +1,9 @@ using System.IO; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +internal interface Line { - internal interface Line - { - void OverwriteCounts(CharacterWidth[] widths); - void Write(TextWriter writer, CharacterWidth[] widths); - } + void OverwriteCounts(CharacterWidth[] widths); + void Write(TextWriter writer, CharacterWidth[] widths); } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/ModelQuery.cs b/src/Lamar/IoC/Diagnostics/ModelQuery.cs index f734cb8e..bd00e35f 100644 --- a/src/Lamar/IoC/Diagnostics/ModelQuery.cs +++ b/src/Lamar/IoC/Diagnostics/ModelQuery.cs @@ -5,55 +5,53 @@ using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.Diagnostics; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +public class ModelQuery { - public class ModelQuery - { - /// - /// Optionally specify the namespace of service types in the query. This is inclusive. - /// - public string Namespace; - - /// - /// Only list out registrations for the specific ServiceType - /// - public Type ServiceType; - - /// - /// Only list out registrations for service types from this assembly - /// - public Assembly Assembly; - - - public string TypeName; - - public IEnumerable Query(IModel model) - { - var enumerable = model.ServiceTypes; + /// + /// Only list out registrations for service types from this assembly + /// + public Assembly Assembly; + + /// + /// Optionally specify the namespace of service types in the query. This is inclusive. + /// + public string Namespace; - if (Namespace.IsNotEmpty()) - { - enumerable = enumerable.Where(x => x.ServiceType.IsInNamespace(Namespace)); - } + /// + /// Only list out registrations for the specific ServiceType + /// + public Type ServiceType; + + + public string TypeName; + + public IEnumerable Query(IModel model) + { + var enumerable = model.ServiceTypes; - if (ServiceType != null) - { - enumerable = enumerable.Where(x => x.ServiceType == ServiceType); - } + if (Namespace.IsNotEmpty()) + { + enumerable = enumerable.Where(x => x.ServiceType.IsInNamespace(Namespace)); + } - if (Assembly != null) - { - enumerable = enumerable.Where(x => x.ServiceType.GetTypeInfo().Assembly == Assembly); - } + if (ServiceType != null) + { + enumerable = enumerable.Where(x => x.ServiceType == ServiceType); + } - if (TypeName.IsNotEmpty()) - { - enumerable = enumerable.Where(x => x.ServiceType.Name.ToLower().Contains(TypeName.ToLower())); - } + if (Assembly != null) + { + enumerable = enumerable.Where(x => x.ServiceType.GetTypeInfo().Assembly == Assembly); + } - return enumerable; + if (TypeName.IsNotEmpty()) + { + enumerable = enumerable.Where(x => x.ServiceType.Name.ToLower().Contains(TypeName.ToLower())); } + + return enumerable; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/TextLine.cs b/src/Lamar/IoC/Diagnostics/TextLine.cs index de84d0b4..acbd324b 100644 --- a/src/Lamar/IoC/Diagnostics/TextLine.cs +++ b/src/Lamar/IoC/Diagnostics/TextLine.cs @@ -1,40 +1,42 @@ using System.IO; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +internal class TextLine : Line { - internal class TextLine : Line - { - private readonly string[] _contents; + private readonly string[] _contents; - internal TextLine(string[] contents) + internal TextLine(string[] contents) + { + _contents = contents; + for (var i = 0; i < contents.Length; i++) { - _contents = contents; - for (var i = 0; i < contents.Length; i++) + if (contents[i] == null) { - if (contents[i] == null) contents[i] = string.Empty; + contents[i] = string.Empty; } } + } - #region Line Members + #region Line Members - public void OverwriteCounts(CharacterWidth[] widths) + public void OverwriteCounts(CharacterWidth[] widths) + { + for (var i = 0; i < widths.Length; i++) { - for (var i = 0; i < widths.Length; i++) - { - var width = widths[i]; - width.SetWidth(_contents[i].Length); - } + var width = widths[i]; + width.SetWidth(_contents[i].Length); } + } - public void Write(TextWriter writer, CharacterWidth[] widths) + public void Write(TextWriter writer, CharacterWidth[] widths) + { + for (var i = 0; i < widths.Length; i++) { - for (var i = 0; i < widths.Length; i++) - { - var width = widths[i]; - writer.Write(_contents[i].PadRight(width.Width)); - } + var width = widths[i]; + writer.Write(_contents[i].PadRight(width.Width)); } - - #endregion } + + #endregion } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/TextReportWriter.cs b/src/Lamar/IoC/Diagnostics/TextReportWriter.cs index f6d7e1fa..0b4c459a 100644 --- a/src/Lamar/IoC/Diagnostics/TextReportWriter.cs +++ b/src/Lamar/IoC/Diagnostics/TextReportWriter.cs @@ -2,92 +2,88 @@ using System.Diagnostics; using System.IO; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +public class TextReportWriter { - public class TextReportWriter + private readonly int _columnCount; + private readonly List _lines = new(); + + public TextReportWriter(int columnCount) { - private readonly int _columnCount; - private readonly List _lines = new List(); + _columnCount = columnCount; + } - public TextReportWriter(int columnCount) - { - _columnCount = columnCount; - } + public void AddDivider(char character) + { + _lines.Add(new DividerLine(character)); + } - public void AddDivider(char character) - { - _lines.Add(new DividerLine(character)); - } + public void AddText(params string[] contents) + { + _lines.Add(new TextLine(contents)); + } - public void AddText(params string[] contents) - { - _lines.Add(new TextLine(contents)); - } + public void AddContent(string contents) + { + _lines.Add(new PlainLine(contents)); + } - public void AddContent(string contents) - { - _lines.Add(new PlainLine(contents)); - } + public void Write(StringWriter writer) + { + var widths = CharacterWidth.For(_columnCount); - public void Write(StringWriter writer) - { - var widths = CharacterWidth.For(_columnCount); - - foreach (var line in _lines) - { - line.OverwriteCounts(widths); - } - - for (var i = 0; i < widths.Length - 1; i++) - { - var width = widths[i]; - width.Add(5); - } - - foreach (var line in _lines) - { - writer.WriteLine(); - line.Write(writer, widths); - } - } + foreach (var line in _lines) line.OverwriteCounts(widths); - public string Write() + for (var i = 0; i < widths.Length - 1; i++) { - using (var writer = new StringWriter()) - { - Write(writer); - - return writer.ToString(); - } + var width = widths[i]; + width.Add(5); } - public void DumpToDebug() + foreach (var line in _lines) { - Debug.WriteLine(Write()); + writer.WriteLine(); + line.Write(writer, widths); } } - internal class PlainLine : Line + public string Write() { - public PlainLine(string contents) + using (var writer = new StringWriter()) { - Contents = contents; + Write(writer); + + return writer.ToString(); } + } - public string Contents { get; set; } + public void DumpToDebug() + { + Debug.WriteLine(Write()); + } +} + +internal class PlainLine : Line +{ + public PlainLine(string contents) + { + Contents = contents; + } - #region Line Members + public string Contents { get; set; } - public void OverwriteCounts(CharacterWidth[] widths) - { - // no-op - } + #region Line Members - public void Write(TextWriter writer, CharacterWidth[] widths) - { - writer.WriteLine(Contents); - } + public void OverwriteCounts(CharacterWidth[] widths) + { + // no-op + } - #endregion + public void Write(TextWriter writer, CharacterWidth[] widths) + { + writer.WriteLine(Contents); } + + #endregion } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/WhatDoIHaveWriter.cs b/src/Lamar/IoC/Diagnostics/WhatDoIHaveWriter.cs index 18ed90b8..09680888 100644 --- a/src/Lamar/IoC/Diagnostics/WhatDoIHaveWriter.cs +++ b/src/Lamar/IoC/Diagnostics/WhatDoIHaveWriter.cs @@ -1,158 +1,155 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.Diagnostics; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +public enum WhatDoIHaveDisplay +{ + Summary, + BuildPlan +} + +public class WhatDoIHaveWriter { - public enum WhatDoIHaveDisplay + private readonly IModel _graph; + + public WhatDoIHaveWriter(IModel graph) { - Summary, - BuildPlan + _graph = graph; } - - public class WhatDoIHaveWriter - { - private readonly IModel _graph; - public WhatDoIHaveWriter(IModel graph) - { - _graph = graph; - } - - public string GetText(ModelQuery query, string title = null, WhatDoIHaveDisplay display = WhatDoIHaveDisplay.Summary) + public string GetText(ModelQuery query, string title = null, + WhatDoIHaveDisplay display = WhatDoIHaveDisplay.Summary) + { + using (var writer = new StringWriter()) { - using (var writer = new StringWriter()) + if (title.IsNotEmpty()) { - if (title.IsNotEmpty()) - { - writer.WriteLine(title); - } + writer.WriteLine(title); + } - writer.WriteLine(""); + writer.WriteLine(""); - var model = _graph; + var model = _graph; - var serviceTypes = query.Query(model); + var serviceTypes = query.Query(model); - writeContentsOfServiceTypes(serviceTypes, writer, display); + writeContentsOfServiceTypes(serviceTypes, writer, display); - return writer.ToString(); - } + return writer.ToString(); } + } - private void writeContentsOfServiceTypes(IEnumerable serviceTypes, - StringWriter writer, WhatDoIHaveDisplay display) + private void writeContentsOfServiceTypes(IEnumerable serviceTypes, + StringWriter writer, WhatDoIHaveDisplay display) + { + if (display == WhatDoIHaveDisplay.Summary) { - if (display == WhatDoIHaveDisplay.Summary) - { - writeSummary(serviceTypes, writer); - } - else - { - writeBuildPlan(serviceTypes, writer); - } + writeSummary(serviceTypes, writer); + } + else + { + writeBuildPlan(serviceTypes, writer); } + } - private static void writeBuildPlan(IEnumerable serviceTypes, StringWriter writer) + private static void writeBuildPlan(IEnumerable serviceTypes, StringWriter writer) + { + foreach (var serviceType in serviceTypes.Where(x => !x.ServiceType.IsOpenGeneric())) { - foreach (var serviceType in serviceTypes.Where(x => !x.ServiceType.IsOpenGeneric())) + writer.WriteLine("------------------------------------------------------------------------"); + writer.WriteLine($"Service Type: {serviceType.ServiceType.FullNameInCode()}"); + + foreach (var instance in serviceType.Instances) { - writer.WriteLine("------------------------------------------------------------------------"); - writer.WriteLine($"Service Type: {serviceType.ServiceType.FullNameInCode()}"); - - foreach (var instance in serviceType.Instances) - { - writer.WriteLine($"Implementation Type: {instance.ImplementationType.FullNameInCode()}"); - writer.WriteLine($"Instance Name: '{instance.Name}'"); - writer.WriteLine(); - writer.WriteLine(instance.DescribeBuildPlan()); - writer.WriteLine(); - } + writer.WriteLine($"Implementation Type: {instance.ImplementationType.FullNameInCode()}"); + writer.WriteLine($"Instance Name: '{instance.Name}'"); + writer.WriteLine(); + writer.WriteLine(instance.DescribeBuildPlan()); + writer.WriteLine(); } } + } - private void writeSummary(IEnumerable serviceTypes, StringWriter writer) - { - var reportWriter = new TextReportWriter(5); + private void writeSummary(IEnumerable serviceTypes, StringWriter writer) + { + var reportWriter = new TextReportWriter(5); - reportWriter.AddDivider('='); - reportWriter.AddText("ServiceType", "Namespace", "Lifecycle", "Description", "Name"); + reportWriter.AddDivider('='); + reportWriter.AddText("ServiceType", "Namespace", "Lifecycle", "Description", "Name"); - serviceTypes.Where(x => x.Instances.Any()).OrderBy(x => x.ServiceType.Name) - .Each(svc => writeServiceType(svc, reportWriter)); + serviceTypes.Where(x => x.Instances.Any()).OrderBy(x => x.ServiceType.Name) + .Each(svc => writeServiceType(svc, reportWriter)); - reportWriter.AddDivider('='); + reportWriter.AddDivider('='); - reportWriter.Write(writer); - } + reportWriter.Write(writer); + } - private void writeServiceType(IServiceFamilyConfiguration serviceType, TextReportWriter reportWriter) - { - reportWriter.AddDivider('-'); + private void writeServiceType(IServiceFamilyConfiguration serviceType, TextReportWriter reportWriter) + { + reportWriter.AddDivider('-'); - var name = serviceType.ServiceType.ShortNameInCode(); - var ns = serviceType.ServiceType.Namespace; + var name = serviceType.ServiceType.ShortNameInCode(); + var ns = serviceType.ServiceType.Namespace; - var contents = new[] - { - name, - ns, - string.Empty, - string.Empty, - string.Empty - }; - - if (name.Length > 75) - { - contents[0] = contents[1] = string.Empty; - reportWriter.AddContent("ServiceType: " + name); - reportWriter.AddContent(" Namespace: " + ns); - } - - var instances = serviceType.Instances.ToArray(); - var instanceRegistry = new List(instances.Length); + var contents = new[] + { + name, + ns, + string.Empty, + string.Empty, + string.Empty + }; + + if (name.Length > 75) + { + contents[0] = contents[1] = string.Empty; + reportWriter.AddContent("ServiceType: " + name); + reportWriter.AddContent(" Namespace: " + ns); + } - setContents(contents, instances[0], instanceRegistry); - reportWriter.AddText(contents); + var instances = serviceType.Instances.ToArray(); + var instanceRegistry = new List(instances.Length); - for (int i = 1; i < serviceType.Instances.Count(); i++) - { - writeInstance(instances[i], serviceType, reportWriter, instanceRegistry); - } + setContents(contents, instances[0], instanceRegistry); + reportWriter.AddText(contents); + + for (var i = 1; i < serviceType.Instances.Count(); i++) + { + writeInstance(instances[i], serviceType, reportWriter, instanceRegistry); } + } - private void writeInstance(InstanceRef instance, IServiceFamilyConfiguration serviceType, - TextReportWriter reportWriter, - List instanceRegistry) + private void writeInstance(InstanceRef instance, IServiceFamilyConfiguration serviceType, + TextReportWriter reportWriter, + List instanceRegistry) + { + if (instanceRegistry.Contains(instance) || instance == null) { - if (instanceRegistry.Contains(instance) || instance == null) - { - return; - } + return; + } - var contents = new[] {string.Empty, string.Empty, string.Empty, string.Empty, string.Empty}; + var contents = new[] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty }; - setContents(contents, instance, instanceRegistry); + setContents(contents, instance, instanceRegistry); - reportWriter.AddText(contents); - } + reportWriter.AddText(contents); + } - private void setContents(string[] contents, InstanceRef instance, List instanceRegistry) - { - contents[2] = instance.Lifetime.ToString(); + private void setContents(string[] contents, InstanceRef instance, List instanceRegistry) + { + contents[2] = instance.Lifetime.ToString(); - contents[3] = instance.ToString().Elid(75); + contents[3] = instance.ToString().Elid(75); - contents[4] = instance.Name.Elid(25); + contents[4] = instance.Name.Elid(25); - instanceRegistry.Add(instance); - } + instanceRegistry.Add(instance); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Diagnostics/WriterExtensions.cs b/src/Lamar/IoC/Diagnostics/WriterExtensions.cs index 7e4a6f66..6e8a76de 100644 --- a/src/Lamar/IoC/Diagnostics/WriterExtensions.cs +++ b/src/Lamar/IoC/Diagnostics/WriterExtensions.cs @@ -1,17 +1,16 @@ using System.IO; -namespace Lamar.IoC.Diagnostics +namespace Lamar.IoC.Diagnostics; + +public static class WriterExtensions { - public static class WriterExtensions + public static void WriteLine(this TextWriter writer, int spaces, string text) { - public static void WriteLine(this TextWriter writer, int spaces, string text) - { - writer.WriteLine("".PadRight(spaces) + text); - } + writer.WriteLine("".PadRight(spaces) + text); + } - public static string Line(this int length, char character) - { - return "".PadRight(length, character); - } + public static string Line(this int length, char character) + { + return "".PadRight(length, character); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Enumerables/ArrayInstance.cs b/src/Lamar/IoC/Enumerables/ArrayInstance.cs index 60b0b773..0f7ca3a5 100644 --- a/src/Lamar/IoC/Enumerables/ArrayInstance.cs +++ b/src/Lamar/IoC/Enumerables/ArrayInstance.cs @@ -1,87 +1,86 @@ using System; using System.Collections.Generic; using System.Linq; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Instances; -using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration.Frames; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Enumerables +namespace Lamar.IoC.Enumerables; + +internal interface IEnumerableInstance +{ + Instance[] Elements { get; } + Type ServiceType { get; } +} + +/// +/// Instance type to represent .Net arrays +/// +/// +public class ArrayInstance : GeneratedInstance, IEnumerableInstance { - internal interface IEnumerableInstance + public ArrayInstance(Type serviceType) : base(serviceType, typeof(T[]), ServiceLifetime.Transient) { - Instance[] Elements { get; } - Type ServiceType { get; } + Name = Variable.DefaultArgName(); } - /// - /// Instance type to represent .Net arrays - /// - /// - public class ArrayInstance : GeneratedInstance, IEnumerableInstance + public IList InlineDependencies { get; } = new List(); + + public Instance[] Elements { get; private set; } + + public override Frame CreateBuildFrame() { - private readonly IList _inlines = new List(); + var variables = new ResolverVariables(); + var elements = Elements.Select(x => variables.Resolve(x, BuildMode.Dependency)).ToArray(); + + variables.MakeNamesUnique(); - public ArrayInstance(Type serviceType) : base(serviceType, typeof(T[]), ServiceLifetime.Transient) + return new ArrayAssignmentFrame(this, elements) { - Name = Variable.DefaultArgName(); - } + ReturnCreated = true + }; + } - public Instance[] Elements { get; private set; } + protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) + { + // This is goofy, but if the current service is the top level root of the resolver + // being created here, make the dependencies all be Dependency mode + var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; - public override Frame CreateBuildFrame() - { - var variables = new ResolverVariables(); - var elements = Elements.Select(x => variables.Resolve(x, BuildMode.Dependency)).ToArray(); - - variables.MakeNamesUnique(); - - return new ArrayAssignmentFrame(this, elements) - { - ReturnCreated = true - }; - } + var elements = Elements.Select(x => variables.Resolve(x, dependencyMode)).ToArray(); - protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) - { - // This is goofy, but if the current service is the top level root of the resolver - // being created here, make the dependencies all be Dependency mode - var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; - - var elements = Elements.Select(x => variables.Resolve(x, dependencyMode)).ToArray(); - - return new ArrayAssignmentFrame(this, elements).Variable; - } + return new ArrayAssignmentFrame(this, elements).Variable; + } - protected override IEnumerable createPlan(ServiceGraph services) + protected override IEnumerable createPlan(ServiceGraph services) + { + if (InlineDependencies.Any()) { - if (_inlines.Any()) - Elements = _inlines.ToArray(); - else - Elements = services.FindAll(typeof(T)); - - return Elements; + Elements = InlineDependencies.ToArray(); } - - public override object QuickResolve(Scope scope) + else { - return Elements.Select(x => x.QuickResolve(scope).As()).ToArray(); + Elements = services.FindAll(typeof(T)); } - /// - /// Adds an inline dependency - /// - /// - public void AddInline(Instance instance) - { - instance.Parent = this; - _inlines.Add(instance); - } + return Elements; + } + + public override object QuickResolve(Scope scope) + { + return Elements.Select(x => x.QuickResolve(scope).As()).ToArray(); + } - public IList InlineDependencies => _inlines; + /// + /// Adds an inline dependency + /// + /// + public void AddInline(Instance instance) + { + instance.Parent = this; + InlineDependencies.Add(instance); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Enumerables/EnumerablePolicy.cs b/src/Lamar/IoC/Enumerables/EnumerablePolicy.cs index b93a2f10..5295d5a7 100644 --- a/src/Lamar/IoC/Enumerables/EnumerablePolicy.cs +++ b/src/Lamar/IoC/Enumerables/EnumerablePolicy.cs @@ -1,37 +1,36 @@ using System; -using System.Collections.Generic; using System.Linq; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Enumerables +namespace Lamar.IoC.Enumerables; + +#region sample_EnumerablePolicy + +internal class EnumerablePolicy : IFamilyPolicy { - #region sample_EnumerablePolicy - internal class EnumerablePolicy : IFamilyPolicy + public ServiceFamily Build(Type type, ServiceGraph serviceGraph) { - public ServiceFamily Build(Type type, ServiceGraph serviceGraph) + if (type.IsArray) { - if (type.IsArray) - { - var instanceType = typeof(ArrayInstance<>).MakeGenericType(type.GetElementType()); - var instance = Activator.CreateInstance(instanceType, type).As(); - return new ServiceFamily(type, new IDecoratorPolicy[0], instance); - } - - if (type.IsEnumerable()) - { - var elementType = type.GetGenericArguments().First(); - - var instanceType = typeof(ListInstance<>).MakeGenericType(elementType); - var ctor = instanceType.GetConstructors().Single(); - var instance = ctor.Invoke(new object[]{type}).As(); - - return new ServiceFamily(type, new IDecoratorPolicy[0], instance); - } - - return null; + var instanceType = typeof(ArrayInstance<>).MakeGenericType(type.GetElementType()); + var instance = Activator.CreateInstance(instanceType, type).As(); + return new ServiceFamily(type, new IDecoratorPolicy[0], instance); } + + if (type.IsEnumerable()) + { + var elementType = type.GetGenericArguments().First(); + + var instanceType = typeof(ListInstance<>).MakeGenericType(elementType); + var ctor = instanceType.GetConstructors().Single(); + var instance = ctor.Invoke(new object[] { type }).As(); + + return new ServiceFamily(type, new IDecoratorPolicy[0], instance); + } + + return null; } - #endregion -} \ No newline at end of file +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/IoC/Enumerables/ListInstance.cs b/src/Lamar/IoC/Enumerables/ListInstance.cs index 468847a7..494c723d 100644 --- a/src/Lamar/IoC/Enumerables/ListInstance.cs +++ b/src/Lamar/IoC/Enumerables/ListInstance.cs @@ -1,85 +1,84 @@ using System; using System.Collections.Generic; using System.Linq; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Frames; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Enumerables +namespace Lamar.IoC.Enumerables; + +/// +/// Instance type to support .Net enumerable types that are not arrays +/// +/// +public class ListInstance : GeneratedInstance, IEnumerableInstance { - /// - /// Instance type to support .Net enumerable types that are not arrays - /// - /// - public class ListInstance : GeneratedInstance, IEnumerableInstance + public ListInstance(Type serviceType) : base(serviceType, typeof(List), ServiceLifetime.Transient) { - private readonly IList _inlines = new List(); + Name = Variable.DefaultArgName(typeof(List)); + } - public ListInstance(Type serviceType) : base(serviceType, typeof(List), ServiceLifetime.Transient) - { - Name = Variable.DefaultArgName(typeof(List)); - } + public IList InlineDependencies { get; } = new List(); - public override Frame CreateBuildFrame() - { - var variables = new ResolverVariables(); - var elements = Elements.Select(x => variables.Resolve(x, BuildMode.Dependency)).ToArray(); - variables.MakeNamesUnique(); - - return new ListAssignmentFrame(this, elements) - { - ReturnCreated = true - }; - } + public Instance[] Elements { get; private set; } - public Instance[] Elements { get; private set; } + public override Frame CreateBuildFrame() + { + var variables = new ResolverVariables(); + var elements = Elements.Select(x => variables.Resolve(x, BuildMode.Dependency)).ToArray(); + variables.MakeNamesUnique(); - protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) + return new ListAssignmentFrame(this, elements) { - // This is goofy, but if the current service is the top level root of the resolver - // being created here, make the dependencies all be Dependency mode - var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; - - var elements = Elements.Select(x => variables.Resolve(x, dependencyMode)).ToArray(); + ReturnCreated = true + }; + } - return new ListAssignmentFrame(this, elements).Variable; - } + protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) + { + // This is goofy, but if the current service is the top level root of the resolver + // being created here, make the dependencies all be Dependency mode + var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; - protected override IEnumerable createPlan(ServiceGraph services) - { - if (_inlines.Any()) - Elements = _inlines.ToArray(); - else - Elements = services.FindAll(typeof(T)); + var elements = Elements.Select(x => variables.Resolve(x, dependencyMode)).ToArray(); - return Elements; - } + return new ListAssignmentFrame(this, elements).Variable; + } - public override object QuickResolve(Scope scope) + protected override IEnumerable createPlan(ServiceGraph services) + { + if (InlineDependencies.Any()) { - return Elements.Select(x => x.QuickResolve(scope).As()).ToList(); + Elements = InlineDependencies.ToArray(); } - - /// - /// Adds an inline dependency - /// - /// - public void AddInline(Instance instance) + else { - instance.Parent = this; - _inlines.Add(instance); + Elements = services.FindAll(typeof(T)); } - public IList InlineDependencies => _inlines; + return Elements; + } - public override string ToString() - { - return $"List of all {typeof(T).NameInCode()}"; - } + public override object QuickResolve(Scope scope) + { + return Elements.Select(x => x.QuickResolve(scope).As()).ToList(); + } + + /// + /// Adds an inline dependency + /// + /// + public void AddInline(Instance instance) + { + instance.Parent = this; + InlineDependencies.Add(instance); + } + + public override string ToString() + { + return $"List of all {typeof(T).NameInCode()}"; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ArrayAssignmentFrame.cs b/src/Lamar/IoC/Frames/ArrayAssignmentFrame.cs index 31f47d16..22137ea8 100644 --- a/src/Lamar/IoC/Frames/ArrayAssignmentFrame.cs +++ b/src/Lamar/IoC/Frames/ArrayAssignmentFrame.cs @@ -2,72 +2,69 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using JasperFx.Core; -using Lamar.IoC.Enumerables; -using Lamar.Scanning.Conventions; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core; +using JasperFx.Core.Reflection; +using Lamar.IoC.Enumerables; + +namespace Lamar.IoC.Frames; -namespace Lamar.IoC.Frames +public class ArrayAssignmentFrame : SyncFrame, IResolverFrame { - public class ArrayAssignmentFrame : SyncFrame, IResolverFrame + public ArrayAssignmentFrame(ArrayInstance instance, Variable[] elements) { - public ArrayAssignmentFrame(ArrayInstance instance, Variable[] elements) - { - Elements = elements; - Variable = new ServiceVariable(instance, this); + Elements = elements; + Variable = new ServiceVariable(instance, this); - ElementType = typeof(T); - } + ElementType = typeof(T); + } + public Type ElementType { get; } - public Type ElementType { get; } + public Variable[] Elements { get; } - public Variable[] Elements { get; } + public Variable Variable { get; } + public bool ReturnCreated { get; set; } + + public void WriteExpressions(LambdaDefinition definition) + { + var init = Expression.NewArrayInit(ElementType, Elements.Select(definition.ExpressionFor)); + var expr = definition.ExpressionFor(Variable); - public Variable Variable { get; } - public bool ReturnCreated { get; set; } + var assign = Expression.Assign(expr, init); + definition.Body.Add(assign); - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + if (Next == null) { - var elements = Elements.Select(x => x.Usage).Join(", "); - - var arrayType = ElementType.FullNameInCode(); - - if (ReturnCreated) - { - writer.Write($"return new {arrayType}[]{{{elements}}};"); - } - else - { - writer.Write($"var {Variable.Usage} = new {arrayType}[]{{{elements}}};"); - } - - - Next?.GenerateCode(method, writer); + definition.Body.Add(expr); } + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + var elements = Elements.Select(x => x.Usage).Join(", "); - public override IEnumerable FindVariables(IMethodVariables chain) + var arrayType = ElementType.FullNameInCode(); + + if (ReturnCreated) { - return Elements; + writer.Write($"return new {arrayType}[]{{{elements}}};"); } - - public void WriteExpressions(LambdaDefinition definition) + else { - var init = Expression.NewArrayInit(ElementType, Elements.Select(definition.ExpressionFor)); - var expr = definition.ExpressionFor(Variable); + writer.Write($"var {Variable.Usage} = new {arrayType}[]{{{elements}}};"); + } - var assign = Expression.Assign(expr, init); - definition.Body.Add(assign); - if (Next == null) - { - definition.Body.Add(expr); - } - } + Next?.GenerateCode(method, writer); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + return Elements; } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ContainerRootField.cs b/src/Lamar/IoC/Frames/ContainerRootField.cs index b48c2c7b..c17a317a 100644 --- a/src/Lamar/IoC/Frames/ContainerRootField.cs +++ b/src/Lamar/IoC/Frames/ContainerRootField.cs @@ -2,30 +2,31 @@ using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public class NestedContainerCreation : AsyncFrame { - public class NestedContainerCreation : AsyncFrame + public NestedContainerCreation() { - public NestedContainerCreation() - { - Root = new InjectedField(typeof(IContainer), "rootContainer"); - Nested = new Variable(typeof(IContainer), "nestedContainer", this); - } + Root = new InjectedField(typeof(IContainer), "rootContainer"); + Nested = new Variable(typeof(IContainer), "nestedContainer", this); + } - public Variable Root { get; } + public Variable Root { get; } - public Variable Nested { get; } + public Variable Nested { get; } - public override IEnumerable FindVariables(IMethodVariables chain) - { - yield return Root; - } + public override IEnumerable FindVariables(IMethodVariables chain) + { + yield return Root; + } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"await using var {Nested.Usage} = ({typeof(IContainer).FullNameInCode()})_rootContainer.{nameof(IContainer.GetNestedContainer)}();"); - Next?.GenerateCode(method, writer); - } + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"await using var {Nested.Usage} = ({typeof(IContainer).FullNameInCode()})_rootContainer.{nameof(IContainer.GetNestedContainer)}();"); + Next?.GenerateCode(method, writer); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/GetInstanceFrame.cs b/src/Lamar/IoC/Frames/GetInstanceFrame.cs index c630f0c6..b6e9bb6d 100644 --- a/src/Lamar/IoC/Frames/GetInstanceFrame.cs +++ b/src/Lamar/IoC/Frames/GetInstanceFrame.cs @@ -2,65 +2,66 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; -using JasperFx.Core.Reflection; -using Lamar.IoC.Instances; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Instances; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +#region sample_GetInstanceFrame + +public class GetInstanceFrame : SyncFrame, IResolverFrame { - - #region sample_GetInstanceFrame - public class GetInstanceFrame : SyncFrame, IResolverFrame + private static readonly MethodInfo _resolveMethod = + ReflectionHelper.GetMethod(x => x.Resolve(null)); + + private readonly string _name; + + + private Variable _scope; + + public GetInstanceFrame(Instance instance) { - private static readonly MethodInfo _resolveMethod = - ReflectionHelper.GetMethod(x => x.Resolve(null)); - - - - private Variable _scope; - private readonly string _name; - - public GetInstanceFrame(Instance instance) - { - Variable = new ServiceVariable(instance, this, ServiceDeclaration.ServiceType); - - _name = instance.Name; - } + Variable = new ServiceVariable(instance, this, ServiceDeclaration.ServiceType); - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInstance)}<{Variable.VariableType.FullNameInCode()}>(\"{_name}\");"); - Next?.GenerateCode(method, writer); - } + _name = instance.Name; + } - public override IEnumerable FindVariables(IMethodVariables chain) - { - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; - } - - public ServiceVariable Variable { get; } - - public void WriteExpressions(LambdaDefinition definition) - { - var scope = definition.Scope(); - var expr = definition.ExpressionFor(Variable); + public ServiceVariable Variable { get; } - var instance = Variable.Instance; + public void WriteExpressions(LambdaDefinition definition) + { + var scope = definition.Scope(); + var expr = definition.ExpressionFor(Variable); + + var instance = Variable.Instance; - var @call = Expression.Call(Expression.Constant(instance), _resolveMethod, scope); - var assign = Expression.Assign(expr, Expression.Convert(@call, Variable.VariableType)); - definition.Body.Add(assign); + var call = Expression.Call(Expression.Constant(instance), _resolveMethod, scope); + var assign = Expression.Assign(expr, Expression.Convert(call, Variable.VariableType)); + definition.Body.Add(assign); - if (Next is null) - { - throw new InvalidCastException($"{typeof(GetInstanceFrame).GetFullName()}.{nameof(Next)} must not be null."); - } + if (Next is null) + { + throw new InvalidCastException( + $"{typeof(GetInstanceFrame).GetFullName()}.{nameof(Next)} must not be null."); } } - #endregion -} \ No newline at end of file + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInstance)}<{Variable.VariableType.FullNameInCode()}>(\"{_name}\");"); + Next?.GenerateCode(method, writer); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; + } +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/GetInstanceFromNestedContainerFrame.cs b/src/Lamar/IoC/Frames/GetInstanceFromNestedContainerFrame.cs index 62d4ad80..91f56845 100644 --- a/src/Lamar/IoC/Frames/GetInstanceFromNestedContainerFrame.cs +++ b/src/Lamar/IoC/Frames/GetInstanceFromNestedContainerFrame.cs @@ -2,14 +2,33 @@ using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; namespace Lamar.IoC.Frames; public class GetInstanceFromNestedContainerFrame : SyncFrame { private readonly Variable _nested; - - + + + public GetInstanceFromNestedContainerFrame(Variable nested, Type serviceType) + { + _nested = nested; + uses.Add(_nested); + + Variable = new Variable(serviceType, this); + } + + /// + /// + /// Optional code fragment to write at the beginning of this + /// type in code + /// + public ICodeFragment? Header { get; set; } + + public Variable Variable { get; } + + /// /// Add a single line comment as the header to this type /// @@ -18,7 +37,7 @@ public void Comment(string text) { Header = new OneLineComment(text); } - + /// /// Add a multi line comment as the header to this type /// @@ -27,24 +46,6 @@ public void MultiLineComment(string text) { Header = new MultiLineComment(text); } - - /// - /// - /// Optional code fragment to write at the beginning of this - /// type in code - /// - public ICodeFragment? Header { get; set; } - - - public GetInstanceFromNestedContainerFrame(Variable nested, Type serviceType) - { - _nested = nested; - uses.Add(_nested); - - Variable = new Variable(serviceType, this); - } - - public Variable Variable { get; } public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) { @@ -53,8 +54,9 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) writer.WriteLine(""); Header.Write(writer); } - - writer.Write($"var {Variable.Usage} = {_nested.Usage}.{nameof(IContainer.GetInstance)}<{Variable.VariableType.FullNameInCode()}>();"); + + writer.Write( + $"var {Variable.Usage} = {_nested.Usage}.{nameof(IContainer.GetInstance)}<{Variable.VariableType.FullNameInCode()}>();"); Next?.GenerateCode(method, writer); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/GetServiceFrame.cs b/src/Lamar/IoC/Frames/GetServiceFrame.cs index 3cd70826..7fe540f2 100644 --- a/src/Lamar/IoC/Frames/GetServiceFrame.cs +++ b/src/Lamar/IoC/Frames/GetServiceFrame.cs @@ -2,27 +2,28 @@ using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public class GetServiceFrame : SyncFrame { - public class GetServiceFrame : SyncFrame - { - private readonly Variable _provider; + private readonly Variable _provider; - public GetServiceFrame(Variable provider, Type serviceType) - { - _provider = provider ?? throw new ArgumentNullException(nameof(provider)); - uses.Add(provider); + public GetServiceFrame(Variable provider, Type serviceType) + { + _provider = provider ?? throw new ArgumentNullException(nameof(provider)); + uses.Add(provider); - Variable = new Variable(serviceType, this); - } + Variable = new Variable(serviceType, this); + } - public Variable Variable { get; } + public Variable Variable { get; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}){_provider.Usage}.{nameof(IServiceProvider.GetService)}(typeof({Variable.VariableType.FullNameInCode()}));"); - Next?.GenerateCode(method, writer); - } + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}){_provider.Usage}.{nameof(IServiceProvider.GetService)}(typeof({Variable.VariableType.FullNameInCode()}));"); + Next?.GenerateCode(method, writer); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/IServiceVariable.cs b/src/Lamar/IoC/Frames/IServiceVariable.cs index 6d880122..39c5a89e 100644 --- a/src/Lamar/IoC/Frames/IServiceVariable.cs +++ b/src/Lamar/IoC/Frames/IServiceVariable.cs @@ -1,9 +1,8 @@ using Lamar.IoC.Instances; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public interface IServiceVariable { - public interface IServiceVariable - { - Instance Instance { get; } - } + Instance Instance { get; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/InjectedServiceField.cs b/src/Lamar/IoC/Frames/InjectedServiceField.cs index eb0d4ef2..dfa92fd3 100644 --- a/src/Lamar/IoC/Frames/InjectedServiceField.cs +++ b/src/Lamar/IoC/Frames/InjectedServiceField.cs @@ -1,60 +1,56 @@ using System; using System.Linq.Expressions; -using JasperFx.Core.Reflection; -using Lamar.IoC.Instances; -using Lamar.Scanning.Conventions; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public class InjectedServiceField : InjectedField, IServiceVariable { - public class InjectedServiceField : InjectedField, IServiceVariable - { - private bool _isOnlyOne; + private bool _isOnlyOne; - public InjectedServiceField(Instance instance) : base(instance.ServiceType, - instance.DefaultArgName()) - { - Instance = instance; - _isOnlyOne = instance.IsOnlyOneOfServiceType; - } + public InjectedServiceField(Instance instance) : base(instance.ServiceType, + instance.DefaultArgName()) + { + Instance = instance; + _isOnlyOne = instance.IsOnlyOneOfServiceType; + } - public bool IsOnlyOne + public bool IsOnlyOne + { + private get => _isOnlyOne; + set { - private get => _isOnlyOne; - set + _isOnlyOne = value; + if (value) { - _isOnlyOne = value; - if (value) - { - var defaultArgName = DefaultArgName(VariableType); - OverrideName("_" +defaultArgName); - CtorArg = defaultArgName; - } + var defaultArgName = DefaultArgName(VariableType); + OverrideName("_" + defaultArgName); + CtorArg = defaultArgName; } } + } - public override string CtorArgDeclaration => - IsOnlyOne - ? $"{ArgType.FullNameInCode()} {CtorArg}" - : $"[Lamar.Named(\"{Instance.Name}\")] {ArgType.FullNameInCode()} {CtorArg}"; + public override string CtorArgDeclaration => + IsOnlyOne + ? $"{ArgType.FullNameInCode()} {CtorArg}" + : $"[Lamar.Named(\"{Instance.Name}\")] {ArgType.FullNameInCode()} {CtorArg}"; - public Instance Instance { get; } + public Instance Instance { get; } - public override Expression ToVariableExpression(LambdaDefinition definition) + public override Expression ToVariableExpression(LambdaDefinition definition) + { + if (Instance.Lifetime == ServiceLifetime.Singleton) { - if (Instance.Lifetime == ServiceLifetime.Singleton) - { - var scope = definition.Context.As(); - var @object = Instance.QuickResolve(scope); - return Expression.Constant(@object); - } - - // This needs to be inlined singletons - throw new NotSupportedException(); + var scope = definition.Context.As(); + var @object = Instance.QuickResolve(scope); + return Expression.Constant(@object); } + + // This needs to be inlined singletons + throw new NotSupportedException(); } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ListAssignmentFrame.cs b/src/Lamar/IoC/Frames/ListAssignmentFrame.cs index e8f8757b..4f6a1ac9 100644 --- a/src/Lamar/IoC/Frames/ListAssignmentFrame.cs +++ b/src/Lamar/IoC/Frames/ListAssignmentFrame.cs @@ -2,74 +2,72 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using JasperFx.Core; -using JasperFx.Core.Reflection; -using Lamar.IoC.Enumerables; -using Lamar.Scanning.Conventions; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core; +using JasperFx.Core.Reflection; +using Lamar.IoC.Enumerables; + +namespace Lamar.IoC.Frames; -namespace Lamar.IoC.Frames +public class ListAssignmentFrame : Frame, IResolverFrame { - public class ListAssignmentFrame : Frame, IResolverFrame + public ListAssignmentFrame(ListInstance instance, Variable[] elements) : base(false) { - public ListAssignmentFrame(ListInstance instance, Variable[] elements) : base(false) - { - ElementType = typeof(T); - Variable = new ServiceVariable(instance, this); + ElementType = typeof(T); + Variable = new ServiceVariable(instance, this); - Elements = elements; - } + Elements = elements; + } + + public Type ElementType { get; } + + public Variable[] Elements { get; } + + public Variable Variable { get; } + public bool ReturnCreated { get; set; } - public Type ElementType { get; } + public void WriteExpressions(LambdaDefinition definition) + { + var listType = typeof(List<>).MakeGenericType(typeof(T)); + var ctor = listType.GetConstructors().Single(x => + x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType.IsEnumerable()); + + var initArray = Expression.NewArrayInit(ElementType, Elements.Select(definition.ExpressionFor)); - public Variable[] Elements { get; } + var expr = definition.ExpressionFor(Variable); - public Variable Variable { get; } - public bool ReturnCreated { get; set; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + var assign = Expression.Assign(expr, Expression.New(ctor, initArray)); + definition.Body.Add(assign); + + if (Next == null) { - var declaration = $"{typeof(List<>).Namespace}.List<{ElementType.FullNameInCode()}>"; - - var elements = Elements.Select(x => x.Usage).Join(", "); - if (ReturnCreated) - { - writer.Write($"return new {declaration}{{{elements}}};"); - } - else - { - writer.Write($"var {Variable.Usage} = new {declaration}{{{elements}}};"); - } - Next?.GenerateCode(method, writer); + definition.Body.Add(expr); } + } - public override IEnumerable FindVariables(IMethodVariables chain) + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + var declaration = $"{typeof(List<>).Namespace}.List<{ElementType.FullNameInCode()}>"; + + var elements = Elements.Select(x => x.Usage).Join(", "); + if (ReturnCreated) { - return Elements; + writer.Write($"return new {declaration}{{{elements}}};"); } - - public void WriteExpressions(LambdaDefinition definition) + else { + writer.Write($"var {Variable.Usage} = new {declaration}{{{elements}}};"); + } - var listType = typeof(List<>).MakeGenericType(typeof(T)); - var ctor = listType.GetConstructors().Single(x => x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType.IsEnumerable()); - - var initArray = Expression.NewArrayInit(ElementType, Elements.Select(definition.ExpressionFor)); - - var expr = definition.ExpressionFor(Variable); - - - var assign = Expression.Assign(expr, Expression.New(ctor, initArray)); - definition.Body.Add(assign); + Next?.GenerateCode(method, writer); + } - if (Next == null) - { - definition.Body.Add(expr); - } - } + public override IEnumerable FindVariables(IMethodVariables chain) + { + return Elements; } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ResolverVariables.cs b/src/Lamar/IoC/Frames/ResolverVariables.cs index b449c85b..d43af92a 100644 --- a/src/Lamar/IoC/Frames/ResolverVariables.cs +++ b/src/Lamar/IoC/Frames/ResolverVariables.cs @@ -2,108 +2,100 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using JasperFx.Core; -using Lamar.IoC.Instances; using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public class ResolverVariables : IEnumerable, IMethodVariables { - public class ResolverVariables : IEnumerable, IMethodVariables + private readonly List _all = new(); + private readonly Dictionary _tracking = new(); + + public ResolverVariables() { - public int VariableSequence { get; set; } - - private readonly List _all = new(); - private readonly Dictionary _tracking = new(); + Method = this; + } - public ResolverVariables() - { - Method = this; - } + public ResolverVariables(IMethodVariables method, IList fields) + { + Method = method; + _all.AddRange(fields); - public ResolverVariables(IMethodVariables method, IList fields) - { - Method = method; - _all.AddRange(fields); + foreach (var field in fields) _tracking[field.Instance] = field; + } - foreach (var field in fields) - { - _tracking[field.Instance] = field; - } - } + public int VariableSequence { get; set; } - public IMethodVariables Method { get; } + public IMethodVariables Method { get; } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } - public IEnumerator GetEnumerator() - { - return _all.GetEnumerator(); - } + public IEnumerator GetEnumerator() + { + return _all.GetEnumerator(); + } - public Variable Resolve(Instance instance, BuildMode mode) - { - if (_tracking.TryGetValue(instance, out var variable)) - { - return variable; - } - - var fromOutside = Method.TryFindVariable(instance.ServiceType, VariableSource.NotServices); - if (fromOutside != null && !(fromOutside is ServiceStandinVariable)) - { - _all.Add(fromOutside); - _tracking[instance] = fromOutside; - - return fromOutside; - } - - variable = instance.CreateVariable(mode, this, false); - _all.Add(variable); - - // Don't track it for possible reuse if it's transient - if (instance.Lifetime == ServiceLifetime.Scoped) - { - _tracking[instance] = variable; - } + Variable IMethodVariables.FindVariable(Type type) + { + return null; + } - return variable; - } + Variable IMethodVariables.FindVariableByName(Type dependency, string name) + { + return null; + } - public void MakeNamesUnique() - { - var duplicateGroups = _all.GroupBy(x => x.Usage).Where(x => x.Count() > 1).ToArray(); - foreach (var @group in duplicateGroups) - { - var i = 0; - foreach (var variable in group) - { - variable.OverrideName(variable.Usage + ++i); - } - } - } + bool IMethodVariables.TryFindVariableByName(Type dependency, string name, out Variable variable) + { + variable = default; + return false; + } - Variable IMethodVariables.FindVariable(Type type) + Variable IMethodVariables.TryFindVariable(Type type, VariableSource source) + { + return null; + } + + public Variable Resolve(Instance instance, BuildMode mode) + { + if (_tracking.TryGetValue(instance, out var variable)) { - return null; + return variable; } - Variable IMethodVariables.FindVariableByName(Type dependency, string name) + var fromOutside = Method.TryFindVariable(instance.ServiceType, VariableSource.NotServices); + if (fromOutside != null && !(fromOutside is ServiceStandinVariable)) { - return null; + _all.Add(fromOutside); + _tracking[instance] = fromOutside; + + return fromOutside; } - bool IMethodVariables.TryFindVariableByName(Type dependency, string name, out Variable variable) + variable = instance.CreateVariable(mode, this, false); + _all.Add(variable); + + // Don't track it for possible reuse if it's transient + if (instance.Lifetime == ServiceLifetime.Scoped) { - variable = default; - return false; + _tracking[instance] = variable; } - Variable IMethodVariables.TryFindVariable(Type type, VariableSource source) + return variable; + } + + public void MakeNamesUnique() + { + var duplicateGroups = _all.GroupBy(x => x.Usage).Where(x => x.Count() > 1).ToArray(); + foreach (var group in duplicateGroups) { - return null; + var i = 0; + foreach (var variable in group) variable.OverrideName(variable.Usage + ++i); } } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ServiceScopeFactoryCreation.cs b/src/Lamar/IoC/Frames/ServiceScopeFactoryCreation.cs index 9298daf5..62d4edcf 100644 --- a/src/Lamar/IoC/Frames/ServiceScopeFactoryCreation.cs +++ b/src/Lamar/IoC/Frames/ServiceScopeFactoryCreation.cs @@ -4,37 +4,34 @@ using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Frames -{ - public class ServiceScopeFactoryCreation : SyncFrame - { - private readonly Variable _factory; - private readonly Variable _scope; +namespace Lamar.IoC.Frames; - public ServiceScopeFactoryCreation() - { +public class ServiceScopeFactoryCreation : SyncFrame +{ + private readonly Variable _factory; + private readonly Variable _scope; - _scope = new Variable(typeof(IServiceScope), this); - Provider = new Variable(typeof(IServiceProvider), this); - Wraps = true; - } + public ServiceScopeFactoryCreation() + { + _scope = new Variable(typeof(IServiceScope), this); + Provider = new Variable(typeof(IServiceProvider), this); + Wraps = true; + } - public ServiceScopeFactoryCreation(Variable factory) : this() - { - _factory = factory; - uses.Add(factory); - } + public ServiceScopeFactoryCreation(Variable factory) : this() + { + _factory = factory; + uses.Add(factory); + } - public Variable Provider { get; } + public Variable Provider { get; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.UsingBlock($"var {_scope.Usage} = {_factory.Usage}.{nameof(IServiceScopeFactory.CreateScope)}()", w => { - writer.UsingBlock($"var {_scope.Usage} = {_factory.Usage}.{nameof(IServiceScopeFactory.CreateScope)}()", w => - { - w.Write($"var {Provider.Usage} = {_scope.Usage}.{nameof(IServiceScope.ServiceProvider)};"); - Next?.GenerateCode(method, w); - }); - } - + w.Write($"var {Provider.Usage} = {_scope.Usage}.{nameof(IServiceScope.ServiceProvider)};"); + Next?.GenerateCode(method, w); + }); } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ServiceStandinVariable.cs b/src/Lamar/IoC/Frames/ServiceStandinVariable.cs index 4972a0e5..ce9ad53c 100644 --- a/src/Lamar/IoC/Frames/ServiceStandinVariable.cs +++ b/src/Lamar/IoC/Frames/ServiceStandinVariable.cs @@ -1,42 +1,44 @@ using System; -using Lamar.IoC.Instances; using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Instances; -namespace Lamar.IoC.Frames -{ - public class ServiceStandinVariable : Variable - { - private Variable _inner; - public Instance Instance { get; } +namespace Lamar.IoC.Frames; - public ServiceStandinVariable(Instance instance) : base(instance.ServiceType) - { - Instance = instance; - } +public class ServiceStandinVariable : Variable +{ + private Variable _inner; - public void UseInner(Variable variable) - { - _inner = variable ?? throw new ArgumentNullException(nameof(variable)); - Dependencies.Add(variable); - } + public ServiceStandinVariable(Instance instance) : base(instance.ServiceType) + { + Instance = instance; + } - public override void OverrideName(string variableName) - { - _inner.OverrideName(variableName); - } + public Instance Instance { get; } - public override string Usage + public override string Usage + { + get => _inner?.Usage; + protected set { - get => _inner?.Usage; - protected set { { base.Usage = value; - }} + } } + } - public override int GetHashCode() - { - return _inner == null ? Instance.GetHashCode() : _inner.GetHashCode(); - } + public void UseInner(Variable variable) + { + _inner = variable ?? throw new ArgumentNullException(nameof(variable)); + Dependencies.Add(variable); + } + + public override void OverrideName(string variableName) + { + _inner.OverrideName(variableName); + } + + public override int GetHashCode() + { + return _inner == null ? Instance.GetHashCode() : _inner.GetHashCode(); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ServiceVariable.cs b/src/Lamar/IoC/Frames/ServiceVariable.cs index da11eb39..7ee15e76 100644 --- a/src/Lamar/IoC/Frames/ServiceVariable.cs +++ b/src/Lamar/IoC/Frames/ServiceVariable.cs @@ -1,24 +1,25 @@ -using System; -using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Instances; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public enum ServiceDeclaration { - public enum ServiceDeclaration - { - ImplementationType, - ServiceType - } - - public class ServiceVariable : Variable, IServiceVariable + ImplementationType, + ServiceType +} + +public class ServiceVariable : Variable, IServiceVariable +{ + public ServiceVariable(Instance instance, Frame creator, + ServiceDeclaration declaration = ServiceDeclaration.ImplementationType) + : base( + declaration == ServiceDeclaration.ImplementationType ? instance.ImplementationType : instance.ServiceType, + instance.Name.Sanitize(), creator) { - public ServiceVariable(Instance instance, Frame creator, ServiceDeclaration declaration = ServiceDeclaration.ImplementationType) - : base(declaration == ServiceDeclaration.ImplementationType ? instance.ImplementationType : instance.ServiceType, instance.Name.Sanitize(), creator) - { - Instance = instance; - } - - public Instance Instance { get; } + Instance = instance; } + + public Instance Instance { get; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/ServiceVariableSource.cs b/src/Lamar/IoC/Frames/ServiceVariableSource.cs index 033af761..cebc7c9f 100644 --- a/src/Lamar/IoC/Frames/ServiceVariableSource.cs +++ b/src/Lamar/IoC/Frames/ServiceVariableSource.cs @@ -1,153 +1,148 @@ using System; using System.Collections.Generic; using System.Linq; -using JasperFx.Core; using JasperFx.CodeGeneration.Model; +using JasperFx.Core; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public class ServiceVariableSource : IServiceVariableSource { - public class ServiceVariableSource : IServiceVariableSource - { - public const string UsingNestedContainerDirectly = @"Using the nested container service location approach + public const string UsingNestedContainerDirectly = @"Using the nested container service location approach because at least one dependency is directl using the Lamar container or IServiceProvider"; - private readonly ServiceGraph _services; - private readonly IList _standins = new List(); + private readonly IList _fields = new List(); + + private readonly ServiceGraph _services; + private readonly IList _standins = new List(); + private Variable _nested = new NestedContainerCreation().Nested; + private bool _usesNestedContainerDirectly; + + public ServiceVariableSource(ServiceGraph services) + { + _services = services; + } - private readonly IList _fields = new List(); - private bool _usesNestedContainerDirectly; - private Variable _nested = new NestedContainerCreation().Nested; + public bool Matches(Type type) + { + return _services.CouldResolve(type); + } - public ServiceVariableSource(ServiceGraph services) + public Variable Create(Type type) + { + if (type == typeof(IContainer)) { - _services = services; + _usesNestedContainerDirectly = true; + return _nested; } - public bool Matches(Type type) + if (type == typeof(IServiceProvider)) { - return _services.CouldResolve(type); + _usesNestedContainerDirectly = true; + return new CastVariable(_nested, typeof(IServiceProvider)); } - public Variable Create(Type type) + var instance = _services.FindDefault(type); + if (instance.Lifetime == ServiceLifetime.Singleton) { - if (type == typeof(IContainer)) + var field = _fields.FirstOrDefault(x => x.Instance == instance); + if (field == null) { - _usesNestedContainerDirectly = true; - return _nested; + field = new InjectedServiceField(instance); + _fields.Add(field); } - if (type == typeof(IServiceProvider)) - { - _usesNestedContainerDirectly = true; - return new CastVariable(_nested, typeof(IServiceProvider)); - } - - var instance = _services.FindDefault(type); - if (instance.Lifetime == ServiceLifetime.Singleton) - { - var field = _fields.FirstOrDefault(x => x.Instance == instance); - if (field == null) - { - field = new InjectedServiceField(instance); - _fields.Add(field); - } - - return field; - } - - var standin = new ServiceStandinVariable(instance); - _standins.Add(standin); - - return standin; + return field; } - public void ReplaceVariables(IMethodVariables method) + var standin = new ServiceStandinVariable(instance); + _standins.Add(standin); + + return standin; + } + + public void ReplaceVariables(IMethodVariables method) + { + if (_usesNestedContainerDirectly || _standins.Any(x => x.Instance.RequiresServiceProvider(method))) { - if (_usesNestedContainerDirectly || _standins.Any(x => x.Instance.RequiresServiceProvider(method))) - { - useServiceProvider(method); - } - else - { - useInlineConstruction(method); - } + useServiceProvider(method); } - - public void StartNewType() + else { - StartNewMethod(); - _fields.Clear(); + useInlineConstruction(method); } + } + + public void StartNewType() + { + StartNewMethod(); + _fields.Clear(); + } + + public void StartNewMethod() + { + _nested = new NestedContainerCreation().Nested; + _standins.Clear(); + } - public void StartNewMethod() + private void useInlineConstruction(IMethodVariables method) + { + // THIS NEEDS TO BE SCOPED PER METHOD!!! + var variables = new ResolverVariables(method, _fields); + foreach (var standin in _standins) { - _nested = new NestedContainerCreation().Nested; - _standins.Clear(); + var variable = variables.Resolve(standin.Instance, BuildMode.Inline); + standin.UseInner(variable); } - private void useInlineConstruction(IMethodVariables method) + variables.OfType().Each(field => { - // THIS NEEDS TO BE SCOPED PER METHOD!!! - var variables = new ResolverVariables(method, _fields); - foreach (var standin in _standins) - { - var variable = variables.Resolve(standin.Instance, BuildMode.Inline); - standin.UseInner(variable); - } + var family = _services.FindAll(field.VariableType); + field.IsOnlyOne = family.Length == 1; + }); - variables.OfType().Each(field => - { - var family = _services.FindAll(field.VariableType); - field.IsOnlyOne = family.Length == 1; - }); - - variables.MakeNamesUnique(); - } + variables.MakeNamesUnique(); + } - private void useServiceProvider(IMethodVariables method) + private void useServiceProvider(IMethodVariables method) + { + var written = false; + foreach (var standin in _standins) { - bool written = false; - foreach (var standin in _standins) + var frame = new GetInstanceFromNestedContainerFrame(_nested, standin.VariableType); + var variable = frame.Variable; + + // Write description of why this had to use the nested container + if (standin.Instance.RequiresServiceProvider(method)) { - var frame = new GetInstanceFromNestedContainerFrame(_nested, standin.VariableType); - var variable = frame.Variable; - - // Write description of why this had to use the nested container - if (standin.Instance.RequiresServiceProvider(method)) - { - var comment = standin.Instance.WhyRequireServiceProvider(method); - - if (_usesNestedContainerDirectly && !written) - { - comment += Environment.NewLine; - comment += UsingNestedContainerDirectly; - - written = true; - } - - frame.MultiLineComment(comment); - } - else if (_usesNestedContainerDirectly && !written) + var comment = standin.Instance.WhyRequireServiceProvider(method); + + if (_usesNestedContainerDirectly && !written) { - frame.MultiLineComment(UsingNestedContainerDirectly); + comment += Environment.NewLine; + comment += UsingNestedContainerDirectly; + written = true; } - - standin.UseInner(variable); - } - var duplicates = _standins.GroupBy(x => x.Usage).Where(x => x.Count() > 1); - foreach (var duplicate in duplicates) + frame.MultiLineComment(comment); + } + else if (_usesNestedContainerDirectly && !written) { - var usage = 0; - foreach (var standinVariable in duplicate) - { - standinVariable.OverrideName(standinVariable.Usage + (++usage)); - } + frame.MultiLineComment(UsingNestedContainerDirectly); + written = true; } + + standin.UseInner(variable); + } + + var duplicates = _standins.GroupBy(x => x.Usage).Where(x => x.Count() > 1); + foreach (var duplicate in duplicates) + { + var usage = 0; + foreach (var standinVariable in duplicate) standinVariable.OverrideName(standinVariable.Usage + ++usage); } } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Frames/VariableExtensions.cs b/src/Lamar/IoC/Frames/VariableExtensions.cs index d003fa75..f5343e62 100644 --- a/src/Lamar/IoC/Frames/VariableExtensions.cs +++ b/src/Lamar/IoC/Frames/VariableExtensions.cs @@ -1,13 +1,12 @@ -using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Model; +using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Instances; -namespace Lamar.IoC.Frames +namespace Lamar.IoC.Frames; + +public static class VariableExtensions { - public static class VariableExtensions + public static bool RefersTo(this Variable variable, Instance instance) { - public static bool RefersTo(this Variable variable, Instance instance) - { - return instance == (variable as IServiceVariable)?.Instance; - } + return instance == (variable as IServiceVariable)?.Instance; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/ConstructorInstance.cs b/src/Lamar/IoC/Instances/ConstructorInstance.cs index 70ce5161..76980c80 100644 --- a/src/Lamar/IoC/Instances/ConstructorInstance.cs +++ b/src/Lamar/IoC/Instances/ConstructorInstance.cs @@ -3,568 +3,587 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using JasperFx.CodeGeneration.Util; using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.IoC.Activation; using Lamar.IoC.Frames; using Lamar.IoC.Setters; using Lamar.Util; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Frames; -using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +/// +/// Models the construction of a service registration that is built by calling the implementation +/// type's constructor functions +/// +/// +/// +public class ConstructorInstance : ConstructorInstance, IMaybeIntercepted + where TImplementation : TService { - /// - /// Models the construction of a service registration that is built by calling the implementation - /// type's constructor functions - /// - /// - /// - public partial class ConstructorInstance : ConstructorInstance, IMaybeIntercepted where TImplementation : TService + private Func _interceptor; + + public ConstructorInstance(Type serviceType, ServiceLifetime lifetime) : base(serviceType, typeof(TImplementation), + lifetime) { - private Func _interceptor; + } - public ConstructorInstance(Type serviceType, ServiceLifetime lifetime) : base(serviceType, typeof(TImplementation), lifetime) + bool IMaybeIntercepted.TryWrap(out Instance wrapped) + { + if (_interceptor != null) { + wrapped = new InterceptingInstance(_interceptor, this); + return true; } - - public ConstructorInstance SelectConstructor(Expression> constructor) - { - var finder = new ConstructorFinderVisitor(typeof(TImplementation)); - finder.Visit(constructor); - Constructor = finder.Constructor; + wrapped = null; + return false; + } - return this; - } - - /// - /// Intercept the object being created and potentially replace it with a wrapped - /// version or another object - /// - /// - /// - public ConstructorInstance OnCreation(Func interceptor) - { - return OnCreation((s, x) => interceptor(x)); - } - - /// - /// Intercept the object being created and potentially replace it with a wrapped - /// version or another object - /// - /// - /// - public ConstructorInstance OnCreation(Func interceptor) - { - _interceptor = interceptor; - return this; - } - - /// - /// Perform some action on the object being created at the time the object is created for the first time by Lamar - /// - /// - /// - public ConstructorInstance OnCreation(Action activator) - { - return OnCreation((s, x) => - { - activator(s, x); - return x; - }); - } - - /// - /// Perform some action on the object being created at the time the object is created for the first time by Lamar - /// - /// - /// - public ConstructorInstance OnCreation(Action activator) - { - return OnCreation((s, x) => - { - activator(x); - return x; - }); - } + public ConstructorInstance SelectConstructor( + Expression> constructor) + { + var finder = new ConstructorFinderVisitor(typeof(TImplementation)); + finder.Visit(constructor); + + Constructor = finder.Constructor; + + return this; + } + + /// + /// Intercept the object being created and potentially replace it with a wrapped + /// version or another object + /// + /// + /// + public ConstructorInstance OnCreation(Func interceptor) + { + return OnCreation((s, x) => interceptor(x)); + } + + /// + /// Intercept the object being created and potentially replace it with a wrapped + /// version or another object + /// + /// + /// + public ConstructorInstance OnCreation( + Func interceptor) + { + _interceptor = interceptor; + return this; + } - bool IMaybeIntercepted.TryWrap(out Instance wrapped) + /// + /// Perform some action on the object being created at the time the object is created for the first time by Lamar + /// + /// + /// + public ConstructorInstance OnCreation(Action activator) + { + return OnCreation((s, x) => { - if (_interceptor != null) - { - wrapped = new InterceptingInstance(_interceptor, this); - return true; - } + activator(s, x); + return x; + }); + } - wrapped = null; - return false; - } + /// + /// Perform some action on the object being created at the time the object is created for the first time by Lamar + /// + /// + /// + public ConstructorInstance OnCreation(Action activator) + { + return OnCreation((s, x) => + { + activator(x); + return x; + }); } +} + +public class ConstructorInstance : GeneratedInstance, IConfiguredInstance +{ + public static readonly string NoPublicConstructors = "No public constructors"; + + public static readonly string NoPublicConstructorCanBeFilled = + "Cannot fill the dependencies of any of the public constructors"; + + + private readonly object _locker = new(); - public class ConstructorInstance : GeneratedInstance, IConfiguredInstance + private readonly List _setters = new(); + + + public ConstructorInstance(Type serviceType, Type implementationType, ServiceLifetime lifetime) : base( + serviceType, implementationType, lifetime) { - public static readonly string NoPublicConstructors = "No public constructors"; + Name = Variable.DefaultArgName(implementationType); + } - public static readonly string NoPublicConstructorCanBeFilled = - "Cannot fill the dependencies of any of the public constructors"; + public CtorArg[] Arguments { get; private set; } = new CtorArg[0]; + public IList InlineDependencies { get; } = new List(); + internal IReadOnlyList Setters => _setters; - public ConstructorInstance(Type serviceType, Type implementationType, ServiceLifetime lifetime) : base( - serviceType, implementationType, lifetime) - { - Name = Variable.DefaultArgName(implementationType); - } + public ConstructorInfo Constructor { get; set; } - public ConstructorInfo Constructor { get; set; } + /// + /// Adds an inline dependency + /// + /// + public void AddInline(Instance instance) + { + instance.Parent = this; + InlineDependencies.Add(instance); + } - public CtorArg[] Arguments { get; private set; } = new CtorArg[0]; - public static ConstructorInstance For(ServiceLifetime lifetime = ServiceLifetime.Transient) - { - return For(lifetime); - } + /// + /// Inline definition of a constructor dependency. Select the constructor argument by type and constructor name. + /// Use this method if there is more than one constructor arguments of the same type + /// + /// + /// + /// + public DependencyExpression Ctor(string constructorArg = null) + { + return new DependencyExpression(this, constructorArg); + } - public static ConstructorInstance For(ServiceLifetime lifetime = ServiceLifetime.Transient) - where TConcrete : T - { - return new(typeof(T), lifetime); - } + IReadOnlyList IConfiguredInstance.InlineDependencies { get; } + + public static ConstructorInstance For(ServiceLifetime lifetime = ServiceLifetime.Transient) + { + return For(lifetime); + } - public IList InlineDependencies => _inlines; + public static ConstructorInstance For( + ServiceLifetime lifetime = ServiceLifetime.Transient) + where TConcrete : T + { + return new ConstructorInstance(typeof(T), lifetime); + } - public override Func ToResolver(Scope topScope) + public override Func ToResolver(Scope topScope) + { + if (Lifetime == ServiceLifetime.Singleton) { - if (Lifetime == ServiceLifetime.Singleton) + return s => { - return s => + if (topScope.Services.TryFind(Hash, out var service)) { - if (topScope.Services.TryFind(Hash, out object service)) - { - return service; - } + return service; + } - lock (_locker) - { - service = ((Func) quickResolve)(topScope); - } + lock (_locker) + { + service = ((Func)quickResolve)(topScope); + } - return service; - }; - } - - return base.ToResolver(topScope); + return service; + }; } - - private readonly object _locker = new object(); - public override object QuickResolve(Scope scope) + return base.ToResolver(topScope); + } + + public override object QuickResolve(Scope scope) + { + if (_resolver != null) { - if (_resolver != null) return _resolver(scope); + return _resolver(scope); + } - if (Lifetime == ServiceLifetime.Singleton) + if (Lifetime == ServiceLifetime.Singleton) + { + lock (_locker) { - lock (_locker) - { - return quickResolve(scope); - } + return quickResolve(scope); } + } - return quickResolve(scope); + return quickResolve(scope); + } + + private object quickResolve(Scope scope) + { + var holdingScope = Lifetime == ServiceLifetime.Singleton ? scope.Root : scope; + if (tryGetService(holdingScope, out var cached)) + { + return cached; } - private object quickResolve(Scope scope) + if (Constructor == null && ErrorMessages.Any()) { - var holdingScope = Lifetime == ServiceLifetime.Singleton ? scope.Root : scope; - if (tryGetService(holdingScope, out var cached)) - { - return cached; - } + new ErrorMessageResolver(this).Resolve(scope); + } - if (Constructor == null && ErrorMessages.Any()) - { - new ErrorMessageResolver(this).Resolve(scope); - } - - var values = Arguments.Select(x => x.Instance.QuickResolve(holdingScope)).ToArray(); - var service = Activator.CreateInstance(ImplementationType, values); + var values = Arguments.Select(x => x.Instance.QuickResolve(holdingScope)).ToArray(); + var service = Activator.CreateInstance(ImplementationType, values); - foreach (var setter in _setters) - { - setter.ApplyQuickBuildProperties(service, scope); - } + foreach (var setter in _setters) setter.ApplyQuickBuildProperties(service, scope); - switch (service) + switch (service) + { + case IDisposable disposable when Lifetime == ServiceLifetime.Singleton: + scope.Root.Disposables.Add(disposable); + break; + case IDisposable disposable: + scope.Disposables.Add(disposable); + break; + case IAsyncDisposable a: { - case IDisposable disposable when Lifetime == ServiceLifetime.Singleton: - scope.Root.Disposables.Add(disposable); - break; - case IDisposable disposable: - scope.Disposables.Add(disposable); - break; - case IAsyncDisposable a: + var wrapper = new AsyncDisposableWrapper(a); + if (Lifetime == ServiceLifetime.Singleton) { - var wrapper = new AsyncDisposableWrapper(a); - if (Lifetime == ServiceLifetime.Singleton) - { - scope.Root.Disposables.Add(wrapper); - } - else - { - scope.Disposables.Add(wrapper); - } - - break; + scope.Root.Disposables.Add(wrapper); + } + else + { + scope.Disposables.Add(wrapper); } - } - if (Lifetime != ServiceLifetime.Transient) - { - store(holdingScope, service); + break; } + } + + if (Lifetime != ServiceLifetime.Transient) + { + store(holdingScope, service); + } + + return service; + } - return service; + public override Instance CloseType(Type serviceType, Type[] templateTypes) + { + if (!ImplementationType.IsOpenGeneric()) + { + return null; } - public override Instance CloseType(Type serviceType, Type[] templateTypes) + Type closedType; + try + { + closedType = ImplementationType.MakeGenericType(templateTypes); + } + catch { - if (!ImplementationType.IsOpenGeneric()) - return null; + return null; + } - Type closedType; - try - { - closedType = ImplementationType.MakeGenericType(templateTypes); - } - catch + var closedInstance = new ConstructorInstance(serviceType, closedType, Lifetime); + foreach (var instance in InlineDependencies) + { + if (instance.ServiceType.IsOpenGeneric()) { - return null; + var closed = instance.CloseType(instance.ServiceType.MakeGenericType(templateTypes), templateTypes); + closedInstance.AddInline(closed); } - - var closedInstance = new ConstructorInstance(serviceType, closedType, Lifetime); - foreach (var instance in InlineDependencies) + else { - if (instance.ServiceType.IsOpenGeneric()) - { - var closed = instance.CloseType(instance.ServiceType.MakeGenericType(templateTypes), templateTypes); - closedInstance.AddInline(closed); - } - else - { - closedInstance.AddInline(instance); - } + closedInstance.AddInline(instance); } - - return closedInstance; } + return closedInstance; + } - protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) - { - var disposalTracking = determineDisposalTracking(mode); - - // This is goofy, but if the current service is the top level root of the resolver - // being created here, make the dependencies all be Dependency mode - var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; - var ctorParameters = Arguments.Select(arg => arg.Resolve(variables, dependencyMode)).ToArray(); - var setterParameters = _setters.Select(arg => arg.Resolve(variables, dependencyMode)).ToArray(); + protected override Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot) + { + var disposalTracking = determineDisposalTracking(mode); - - return new InstanceConstructorFrame(this, disposalTracking, ctorParameters, setterParameters).Variable; - } + // This is goofy, but if the current service is the top level root of the resolver + // being created here, make the dependencies all be Dependency mode + var dependencyMode = isRoot && mode == BuildMode.Build ? BuildMode.Dependency : mode; + var ctorParameters = Arguments.Select(arg => arg.Resolve(variables, dependencyMode)).ToArray(); + var setterParameters = _setters.Select(arg => arg.Resolve(variables, dependencyMode)).ToArray(); - public override Frame CreateBuildFrame() - { - var variables = new ResolverVariables(); - var ctorParameters = Arguments.Select(arg => arg.Resolve(variables, BuildMode.Dependency)).ToArray(); - var setterParameters = _setters.Select(arg => arg.Resolve(variables, BuildMode.Dependency)).ToArray(); - - variables.MakeNamesUnique(); + return new InstanceConstructorFrame(this, disposalTracking, ctorParameters, setterParameters).Variable; + } - return new InstanceConstructorFrame(this, DisposeTracking.None, ctorParameters, setterParameters) - { - Mode = ConstructorCallMode.ReturnValue - }; - } - private DisposeTracking determineDisposalTracking(BuildMode mode) - { - if (!ImplementationType.CanBeCastTo() && !ImplementationType.CanBeCastTo()) return DisposeTracking.None; + public override Frame CreateBuildFrame() + { + var variables = new ResolverVariables(); + var ctorParameters = Arguments.Select(arg => arg.Resolve(variables, BuildMode.Dependency)).ToArray(); - switch (mode) - { - case BuildMode.Inline: - return DisposeTracking.WithUsing; + var setterParameters = _setters.Select(arg => arg.Resolve(variables, BuildMode.Dependency)).ToArray(); - case BuildMode.Dependency: - return DisposeTracking.RegisterWithScope; + variables.MakeNamesUnique(); - case BuildMode.Build: - return DisposeTracking.None; - } + return new InstanceConstructorFrame(this, DisposeTracking.None, ctorParameters, setterParameters) + { + Mode = ConstructorCallMode.ReturnValue + }; + } + private DisposeTracking determineDisposalTracking(BuildMode mode) + { + if (!ImplementationType.CanBeCastTo() && !ImplementationType.CanBeCastTo()) + { return DisposeTracking.None; } + switch (mode) + { + case BuildMode.Inline: + return DisposeTracking.WithUsing; + case BuildMode.Dependency: + return DisposeTracking.RegisterWithScope; - protected override IEnumerable createPlan(ServiceGraph services) - { - Constructor = DetermineConstructor(services, out var message); + case BuildMode.Build: + return DisposeTracking.None; + } - if (message.IsNotEmpty()) ErrorMessages.Add(message); + return DisposeTracking.None; + } - if (Constructor != null) - { - buildOutConstructorArguments(services); - findSetters(services); - } - return Arguments.Select(x => x.Instance).Concat(_setters.Select(x => x.Instance)); - } - - private readonly List _setters = new List(); + protected override IEnumerable createPlan(ServiceGraph services) + { + Constructor = DetermineConstructor(services, out var message); - internal IReadOnlyList Setters => _setters; + if (message.IsNotEmpty()) + { + ErrorMessages.Add(message); + } - internal InjectedSetter[] FindSetters(ServiceGraph services) + if (Constructor != null) { + buildOutConstructorArguments(services); findSetters(services); - return _setters.ToArray(); } - private void findSetters(ServiceGraph services) + return Arguments.Select(x => x.Instance).Concat(_setters.Select(x => x.Instance)); + } + + internal InjectedSetter[] FindSetters(ServiceGraph services) + { + findSetters(services); + return _setters.ToArray(); + } + + private void findSetters(ServiceGraph services) + { + foreach (var property in ImplementationType.GetProperties().Where(x => x.CanWrite && x.SetMethod.IsPublic)) { - foreach (var property in ImplementationType.GetProperties().Where(x => x.CanWrite && x.SetMethod.IsPublic)) + var instance = findInlineDependency(property.Name, property.PropertyType); + if (instance == null && services.ShouldBeSet(property)) { - var instance = findInlineDependency(property.Name, property.PropertyType); - if (instance == null && services.ShouldBeSet(property)) - { - instance = services.FindDefault(property.PropertyType); - } - - if (instance != null) _setters.Add(new InjectedSetter(property, instance)); + instance = services.FindDefault(property.PropertyType); } - - foreach (var setter in _setters) + + if (instance != null) { - setter.Instance.CreatePlan(services); + _setters.Add(new InjectedSetter(property, instance)); } } - private void buildOutConstructorArguments(ServiceGraph services) - { - Arguments = Constructor.GetParameters() - .Select(x => determineArgument(services, x)) - .Where(x => x.Instance != null).ToArray(); + foreach (var setter in _setters) setter.Instance.CreatePlan(services); + } + + private void buildOutConstructorArguments(ServiceGraph services) + { + Arguments = Constructor.GetParameters() + .Select(x => determineArgument(services, x)) + .Where(x => x.Instance != null).ToArray(); + + + foreach (var argument in Arguments) argument.Instance.CreatePlan(services); + } + + + private CtorArg determineArgument(ServiceGraph services, ParameterInfo parameter) + { + var dependencyType = parameter.ParameterType; + var instance = findInstanceForConstructorParameter(services, parameter, dependencyType); + + return new CtorArg(parameter, instance); + } + private Instance findInstanceForConstructorParameter(ServiceGraph services, ParameterInfo parameter, + Type dependencyType) + { + var instance = findInlineDependency(parameter.Name, dependencyType); + if (instance != null) + { + return instance; + } - foreach (var argument in Arguments) + if (parameter.IsOptional) + { + if (parameter.DefaultValue == null) { - argument.Instance.CreatePlan(services); + return services.FindInstance(parameter) ?? new NullInstance(dependencyType); } + + return new ObjectInstance(parameter.ParameterType, parameter.DefaultValue); } + return services.FindInstance(parameter); + } - private CtorArg determineArgument(ServiceGraph services, ParameterInfo parameter) + private Instance findInlineDependency(string name, Type dependencyType) + { + var exact = InlineDependencies.FirstOrDefault(i => i.ServiceType == dependencyType && i.Name == name); + if (exact != null) { - var dependencyType = parameter.ParameterType; - var instance = findInstanceForConstructorParameter(services, parameter, dependencyType); - - return new CtorArg(parameter, instance); + return exact; } - private Instance findInstanceForConstructorParameter(ServiceGraph services, ParameterInfo parameter, Type dependencyType) + var instance = InlineDependencies.FirstOrDefault(i => i.ServiceType == dependencyType); + if (instance == null) { - var instance = findInlineDependency(parameter.Name, dependencyType); - if (instance != null) return instance; + return null; + } - if (parameter.IsOptional) - { - if (parameter.DefaultValue == null) - { - return services.FindInstance(parameter) ?? new NullInstance(dependencyType); - } + return instance.InlineIsLimitedToExactNameMatch ? null : instance; + } - return new ObjectInstance(parameter.ParameterType, parameter.DefaultValue); - } - return services.FindInstance(parameter); + public override string ToString() + { + var text = $"new {ImplementationType.ShortNameInCode()}()"; + if (Constructor != null) + { + text = + $"new {ImplementationType.ShortNameInCode()}({Constructor.GetParameters().Select(x => x.Name).Join(", ")})"; } - private Instance findInlineDependency(string name, Type dependencyType) - { - var exact = _inlines.FirstOrDefault(i => i.ServiceType == dependencyType && i.Name == name); - if (exact != null) return exact; + return text; + } + + private static ConstructorInfo[] findConstructors(Type implementationType) + { + var publics = implementationType.GetConstructors() ?? new ConstructorInfo[0]; - var instance = _inlines.FirstOrDefault(i => i.ServiceType == dependencyType); - if (instance == null) return null; - return instance.InlineIsLimitedToExactNameMatch ? null : instance; + if (publics.Any()) + { + return publics; } - public override string ToString() + if (implementationType.IsPublic) { - string text = $"new {ImplementationType.ShortNameInCode()}()"; - - if (Constructor != null) - { - text = $"new {ImplementationType.ShortNameInCode()}({Constructor.GetParameters().Select(x => x.Name).Join(", ")})"; - } - - return text; + return new ConstructorInfo[0]; } - private static ConstructorInfo[] findConstructors(Type implementationType) - { - var publics = implementationType.GetConstructors() ?? new ConstructorInfo[0]; - if (publics.Any()) return publics; - - - - if (implementationType.IsPublic) - { - return new ConstructorInfo[0]; - } + return implementationType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance | + BindingFlags.Public) ?? new ConstructorInfo[0]; + } + private bool couldBuild(ConstructorInfo ctor, ServiceGraph services) + { + return ctor.GetParameters().All(p => + services.FindDefault(p.ParameterType) != null || + InlineDependencies.Any(x => x.ServiceType == p.ParameterType) || + p.IsOptional); + } - return implementationType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance | - BindingFlags.Public) ?? new ConstructorInfo[0]; + public ConstructorInfo DetermineConstructor(ServiceGraph services, + out string message) + { + message = null; + if (Constructor != null) + { + return Constructor; } - private bool couldBuild(ConstructorInfo ctor, ServiceGraph services) + var fromAttribute = DefaultConstructorAttribute.GetConstructor(ImplementationType); + if (fromAttribute != null) { - return ctor.GetParameters().All(p => - services.FindDefault(p.ParameterType) != null || _inlines.Any(x => x.ServiceType == p.ParameterType) || - p.IsOptional); + return fromAttribute; } - - public ConstructorInfo DetermineConstructor(ServiceGraph services, - out string message) - { - message = null; - - if (Constructor != null) return Constructor; - var fromAttribute = DefaultConstructorAttribute.GetConstructor(ImplementationType); - if (fromAttribute != null) return fromAttribute; + var constructors = findConstructors(ImplementationType); - var constructors = findConstructors(ImplementationType); + if (constructors.Any()) + { + var ctor = constructors + .OrderByDescending(x => x.GetParameters().Length) + .FirstOrDefault(x => couldBuild(x, services)); - if (constructors.Any()) + if (ctor == null) { - var ctor = constructors - .OrderByDescending(x => x.GetParameters().Length) - .FirstOrDefault(x => couldBuild(x, services)); + message = NoPublicConstructorCanBeFilled; + message += $"{Environment.NewLine}Available constructors:"; - if (ctor == null) + foreach (var constructor in constructors) { - message = NoPublicConstructorCanBeFilled; - message += $"{Environment.NewLine}Available constructors:"; - - foreach (var constructor in constructors) - { - message += explainWhyConstructorCannotBeUsed(ImplementationType, constructor, services); - message += Environment.NewLine; - } - + message += explainWhyConstructorCannotBeUsed(ImplementationType, constructor, services); + message += Environment.NewLine; } - - return ctor; } - message = NoPublicConstructors; - - return null; + return ctor; } - private static string explainWhyConstructorCannotBeUsed(Type implementationType, ConstructorInfo constructor, - ServiceGraph services) - { + message = NoPublicConstructors; + + return null; + } - var args = constructor.GetParameters().Select(x => $"{x.ParameterType.NameInCode()} {x.Name}").Join(", "); - var declaration = $"new {implementationType.NameInCode()}({args})"; + private static string explainWhyConstructorCannotBeUsed(Type implementationType, ConstructorInfo constructor, + ServiceGraph services) + { + var args = constructor.GetParameters().Select(x => $"{x.ParameterType.NameInCode()} {x.Name}").Join(", "); + var declaration = $"new {implementationType.NameInCode()}({args})"; - foreach (var parameter in constructor.GetParameters()) + foreach (var parameter in constructor.GetParameters()) + { + if (parameter.ParameterType.ShouldIgnore()) + { + declaration += + $"{Environment.NewLine}* {parameter.ParameterType.NameInCode()} {parameter.Name} is a 'simple' type that cannot be auto-filled"; + } + else { - if (parameter.ParameterType.ShouldIgnore()) + var @default = services.FindDefault(parameter.ParameterType); + if (@default == null) { declaration += - $"{Environment.NewLine}* {parameter.ParameterType.NameInCode()} {parameter.Name} is a 'simple' type that cannot be auto-filled"; - } - else - { - var @default = services.FindDefault(parameter.ParameterType); - if (@default == null) - { - declaration += - $"{Environment.NewLine}* {parameter.ParameterType.NameInCode()} is not registered within this container and cannot be auto discovered by any missing family policy"; - } + $"{Environment.NewLine}* {parameter.ParameterType.NameInCode()} is not registered within this container and cannot be auto discovered by any missing family policy"; } } + } - - return declaration; - } - - private readonly IList _inlines = new List(); - - /// - /// Adds an inline dependency - /// - /// - public void AddInline(Instance instance) - { - instance.Parent = this; - _inlines.Add(instance); - } - - - /// - /// Inline definition of a constructor dependency. Select the constructor argument by type and constructor name. - /// Use this method if there is more than one constructor arguments of the same type - /// - /// - /// - /// - public DependencyExpression Ctor(string constructorArg = null) - { - return new DependencyExpression(this, constructorArg); - } - - /// - /// Inline definition of a setter dependency. Select the setter property by type and optionally by property name. - /// Use this method if there is more than one constructor arguments of the same type - /// - /// - /// - /// - public DependencyExpression Setter(string propName = null) - { - return new DependencyExpression(this, propName); - } + return declaration; + } - IReadOnlyList IConfiguredInstance.InlineDependencies { get; } + /// + /// Inline definition of a setter dependency. Select the setter property by type and optionally by property name. + /// Use this method if there is more than one constructor arguments of the same type + /// + /// + /// + /// + public DependencyExpression Setter(string propName = null) + { + return new DependencyExpression(this, propName); + } - protected override IEnumerable relatedAssemblies() - { - return base.relatedAssemblies().Concat(_inlines.SelectMany(x => x.ReferencedAssemblies())); - } + protected override IEnumerable relatedAssemblies() + { + return base.relatedAssemblies().Concat(InlineDependencies.SelectMany(x => x.ReferencedAssemblies())); } - - -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/CtorArg.cs b/src/Lamar/IoC/Instances/CtorArg.cs index 800c5bfd..5449ab02 100644 --- a/src/Lamar/IoC/Instances/CtorArg.cs +++ b/src/Lamar/IoC/Instances/CtorArg.cs @@ -1,46 +1,44 @@ using System; using System.Reflection; +using JasperFx.CodeGeneration.Model; using JasperFx.Core; using Lamar.IoC.Frames; -using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class CtorArg { - public class CtorArg + public CtorArg(ParameterInfo parameter, Instance instance) { - public ParameterInfo Parameter { get; } - public Instance Instance { get; } - - public CtorArg(ParameterInfo parameter, Instance instance) + try { - try - { - Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); - Instance = instance ?? throw new ArgumentNullException(nameof(instance)); - - if (instance.IsInlineDependency() || instance is LambdaInstance && instance.ServiceType.IsGenericType) - { - instance.Name = Parameter.Name; - } - } - catch (Exception e) + Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); + Instance = instance ?? throw new ArgumentNullException(nameof(instance)); + + if (instance.IsInlineDependency() || (instance is LambdaInstance && instance.ServiceType.IsGenericType)) { - throw new InvalidOperationException( - $"Cannot create a Constructor Argument for {parameter.Name} of {instance}", e); + instance.Name = Parameter.Name; } } - - public Variable Resolve(ResolverVariables variables, BuildMode mode) + catch (Exception e) { - var variable = variables.Resolve(Instance, mode); - - if (Parameter.Name.EqualsIgnoreCase(variable.Usage)) - { - variable.OverrideName("inline_" + variable.Usage); - } + throw new InvalidOperationException( + $"Cannot create a Constructor Argument for {parameter.Name} of {instance}", e); + } + } + + public ParameterInfo Parameter { get; } + public Instance Instance { get; } - return variable; + public Variable Resolve(ResolverVariables variables, BuildMode mode) + { + var variable = variables.Resolve(Instance, mode); + + if (Parameter.Name.EqualsIgnoreCase(variable.Usage)) + { + variable.OverrideName("inline_" + variable.Usage); } + + return variable; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/DependencyExpression.cs b/src/Lamar/IoC/Instances/DependencyExpression.cs index 77892a08..cd12f8e4 100644 --- a/src/Lamar/IoC/Instances/DependencyExpression.cs +++ b/src/Lamar/IoC/Instances/DependencyExpression.cs @@ -1,133 +1,136 @@ using System; -using System.Linq.Expressions; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +/// +/// Expression Builder that helps to define child dependencies inline +/// +public class DependencyExpression { + private readonly ConstructorInstance _instance; + private readonly string _propertyName; + + internal DependencyExpression(ConstructorInstance instance, string propertyName) + { + _instance = instance; + _propertyName = propertyName; + } + + /// - /// Expression Builder that helps to define child dependencies inline + /// Inline dependency by simple Lambda expression /// - public class DependencyExpression + /// + /// + public ConstructorInstance Is(Func func) { - private readonly ConstructorInstance _instance; - private readonly string _propertyName; - - internal DependencyExpression(ConstructorInstance instance, string propertyName) - { - _instance = instance; - _propertyName = propertyName; - } + var child = LambdaInstance.For(func); + return Is(child); + } + /// + /// Inline dependency by Lambda Func that uses IContext + /// + /// User friendly description for diagnostics + /// + /// + public ConstructorInstance Is(string description, Func func) + { + var child = LambdaInstance.For(func); + child.Description = description; + return Is(child); + } - /// - /// Inline dependency by simple Lambda expression - /// - /// - /// - public ConstructorInstance Is(Func func) + /// + /// Shortcut to set an inline dependency to an Instance + /// + /// + /// + public ConstructorInstance Is(Instance instance) + { + _instance.AddInline(instance); + if (_propertyName != null) { - var child = LambdaInstance.For(func); - return Is(child); + instance.Name = _propertyName; + instance.InlineIsLimitedToExactNameMatch = true; } - /// - /// Inline dependency by Lambda Func that uses IContext - /// - /// User friendly description for diagnostics - /// - /// - public ConstructorInstance Is(string description, Func func) - { - var child = LambdaInstance.For(func); - child.Description = description; - return Is(child); - } + return _instance; + } - /// - /// Shortcut to set an inline dependency to an Instance - /// - /// - /// - public ConstructorInstance Is(Instance instance) + /// + /// Shortcut to set an inline dependency to a designated object + /// + /// + /// + public ConstructorInstance Is(TChild value) + { + // TODO -- allow nulls some day, because folks always wanna do crazy + // stuff with them + if (value == null) { - _instance.AddInline(instance); - if (_propertyName != null) - { - instance.Name = _propertyName; - instance.InlineIsLimitedToExactNameMatch = true; - } - return _instance; + throw new ArgumentNullException(nameof(value)); } - /// - /// Shortcut to set an inline dependency to a designated object - /// - /// - /// - public ConstructorInstance Is(TChild value) - { - // TODO -- allow nulls some day, because folks always wanna do crazy - // stuff with them - if (value == null) throw new ArgumentNullException(nameof(value)); - - return Is(new ObjectInstance(typeof(TChild), value)); - } + return Is(new ObjectInstance(typeof(TChild), value)); + } - /// - /// Set the inline dependency to the named instance of the property type - /// Used mostly to force an optional Setter property to be filled by - /// StructureMap /// - /// - /// - public ConstructorInstance IsNamedInstance(string instanceKey) - { - return Is(new ReferencedInstance(typeof(TChild), instanceKey)); - } + /// + /// Set the inline dependency to the named instance of the property type + /// Used mostly to force an optional Setter property to be filled by + /// StructureMap /// + /// + /// + /// + public ConstructorInstance IsNamedInstance(string instanceKey) + { + return Is(new ReferencedInstance(typeof(TChild), instanceKey)); + } - /// - /// Shortcut method to define a child dependency inline - /// - /// - /// - public ConstructorInstance Is() where TConcreteType : TChild - { - return Is(new ConstructorInstance(typeof(TChild), ServiceLifetime.Transient)); - } + /// + /// Shortcut method to define a child dependency inline + /// + /// + /// + public ConstructorInstance Is() where TConcreteType : TChild + { + return Is(new ConstructorInstance(typeof(TChild), ServiceLifetime.Transient)); + } - /// - /// Shortcut method to define a child dependency as null - /// - /// - public ConstructorInstance IsNull() - { - return Is(new NullInstance(typeof(TChild))); - } + /// + /// Shortcut method to define a child dependency as null + /// + /// + public ConstructorInstance IsNull() + { + return Is(new NullInstance(typeof(TChild))); + } - /// - /// Shortcut method to define a child dependency inline and configure - /// the child dependency - /// - /// - /// - public ConstructorInstance Is(Action> configure) where TConcreteType : TChild - { - var instance = new ConstructorInstance(typeof(TChild), ServiceLifetime.Transient); - configure(instance); - return Is(instance); - } + /// + /// Shortcut method to define a child dependency inline and configure + /// the child dependency + /// + /// + /// + public ConstructorInstance Is(Action> configure) + where TConcreteType : TChild + { + var instance = new ConstructorInstance(typeof(TChild), ServiceLifetime.Transient); + configure(instance); + return Is(instance); + } - /// - /// Use the named Instance of TChild for the inline - /// dependency here - /// - /// - /// - public ConstructorInstance Named(string name) - { - return Is(c => c.GetInstance(name)); - } + /// + /// Use the named Instance of TChild for the inline + /// dependency here + /// + /// + /// + public ConstructorInstance Named(string name) + { + return Is(c => c.GetInstance(name)); } - } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/DisposeTracking.cs b/src/Lamar/IoC/Instances/DisposeTracking.cs index 1710a747..295782e2 100644 --- a/src/Lamar/IoC/Instances/DisposeTracking.cs +++ b/src/Lamar/IoC/Instances/DisposeTracking.cs @@ -1,9 +1,8 @@ -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public enum DisposeTracking { - public enum DisposeTracking - { - WithUsing, - RegisterWithScope, - None - } + WithUsing, + RegisterWithScope, + None } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/ErrorMessageResolver.cs b/src/Lamar/IoC/Instances/ErrorMessageResolver.cs index 58609f3e..8d283392 100644 --- a/src/Lamar/IoC/Instances/ErrorMessageResolver.cs +++ b/src/Lamar/IoC/Instances/ErrorMessageResolver.cs @@ -1,37 +1,36 @@ using System; using System.Linq; using JasperFx.Core; +using JasperFx.Core.Reflection; using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class ErrorMessageResolver : IResolver { - public class ErrorMessageResolver : IResolver + private readonly string _message; + + public ErrorMessageResolver(Instance instance) { - private readonly string _message; + ServiceType = instance.ServiceType; + Name = instance.Name; + Hash = instance.GetHashCode(); - public ErrorMessageResolver(Instance instance) + var dependencyProblems = instance.Dependencies.SelectMany(dep => { - ServiceType = instance.ServiceType; - Name = instance.Name; - Hash = instance.GetHashCode(); + return dep.ErrorMessages.Select(x => $"Dependency {dep}: {x}"); + }); - var dependencyProblems = instance.Dependencies.SelectMany(dep => - { - return dep.ErrorMessages.Select(x => $"Dependency {dep}: {x}"); - }); - - _message = instance.ErrorMessages.Concat(dependencyProblems).Join(Environment.NewLine); - } - - public object Resolve(Scope scope) - { - throw new LamarException($"Cannot build registered instance {Name} of '{ServiceType.FullNameInCode()}':{Environment.NewLine}{_message}"); - } + _message = instance.ErrorMessages.Concat(dependencyProblems).Join(Environment.NewLine); + } - public Type ServiceType { get; } - public string Name { get; set; } - public int Hash { get; set; } + public object Resolve(Scope scope) + { + throw new LamarException( + $"Cannot build registered instance {Name} of '{ServiceType.FullNameInCode()}':{Environment.NewLine}{_message}"); } + + public Type ServiceType { get; } + public string Name { get; set; } + public int Hash { get; set; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/FuncResolverDefinition.cs b/src/Lamar/IoC/Instances/FuncResolverDefinition.cs index 58189fbc..ea3ca9ca 100644 --- a/src/Lamar/IoC/Instances/FuncResolverDefinition.cs +++ b/src/Lamar/IoC/Instances/FuncResolverDefinition.cs @@ -1,67 +1,66 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using JasperFx.Core.Reflection; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class FuncResolverDefinition : IGeneratedType, IGeneratedMethod { - public class FuncResolverDefinition : IGeneratedType, IGeneratedMethod + private readonly FramesCollection _frames; + private readonly GenerationRules _rules; + private readonly Scope _scope; + private readonly Argument _scopeArgument; + + public FuncResolverDefinition(GeneratedInstance instance, Scope scope, GenerationRules rules = null) { - private readonly Scope _scope; - private readonly Argument _scopeArgument; - private readonly GenerationRules _rules; - private readonly FramesCollection _frames; + _scope = scope; + _rules = rules ?? new GenerationRules("Jasper.Generated"); + _scopeArgument = new Argument(typeof(Scope), "scope"); + var frame = instance.CreateBuildFrame(); - public FuncResolverDefinition(GeneratedInstance instance, Scope scope, GenerationRules rules = null) - { - _scope = scope; - _rules = rules ?? new GenerationRules("Jasper.Generated"); - _scopeArgument = new Argument(typeof(Scope), "scope"); - var frame = instance.CreateBuildFrame(); + _frames = new FramesCollection(null) { frame }; + } - _frames = new FramesCollection(null) { frame }; - } + FramesCollection IGeneratedMethod.Frames => _frames; + public Argument[] Arguments => new[] { _scopeArgument }; + IList IGeneratedMethod.DerivedVariables { get; } = new List(); + IList IGeneratedMethod.Sources { get; } = new List(); + public string MethodName => "Resolve"; - IList IGeneratedType.Setters { get; } = new List(); - IList IGeneratedType.AllInjectedFields { get; } = new List(); - GenerationRules IGeneratedType.Rules => _rules; - public string TypeName => "FuncResolverDefinition"; - FramesCollection IGeneratedMethod.Frames => _frames; - public Argument[] Arguments => new Argument[] { _scopeArgument }; - IList IGeneratedMethod.DerivedVariables { get; } = new List(); - IList IGeneratedMethod.Sources { get; } = new List(); - public string MethodName => "Resolve"; + IList IGeneratedType.Setters { get; } = new List(); + IList IGeneratedType.AllInjectedFields { get; } = new List(); + GenerationRules IGeneratedType.Rules => _rules; + public string TypeName => "FuncResolverDefinition"; - public Func BuildResolver() - { - var arranger = new MethodFrameArranger(this, this); - arranger.Arrange(out var mode, out var top); + public Func BuildResolver() + { + var arranger = new MethodFrameArranger(this, this); + arranger.Arrange(out var mode, out var top); - var definition = new LambdaDefinition - { - Context = _scope - }; - var scope = definition.RegisterExpression(_scopeArgument).As(); - definition.Arguments = new[] { scope }; + var definition = new LambdaDefinition + { + Context = _scope + }; + var scope = definition.RegisterExpression(_scopeArgument).As(); + definition.Arguments = new[] { scope }; - if (top is not IResolverFrame) - { - throw new InvalidOperationException($"Frame type {top} does not implement {nameof(IResolverFrame)}"); - } + if (top is not IResolverFrame) + { + throw new InvalidOperationException($"Frame type {top} does not implement {nameof(IResolverFrame)}"); + } - var current = top; - do - { - var frame = current.As(); - frame.WriteExpressions(definition); - current = current.Next; - } while (current is not null); + var current = top; + do + { + var frame = current.As(); + frame.WriteExpressions(definition); + current = current.Next; + } while (current is not null); - return definition.Compile>(); - } + return definition.Compile>(); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/GeneratedInstance.cs b/src/Lamar/IoC/Instances/GeneratedInstance.cs index 17a5a221..c076850d 100644 --- a/src/Lamar/IoC/Instances/GeneratedInstance.cs +++ b/src/Lamar/IoC/Instances/GeneratedInstance.cs @@ -2,237 +2,234 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using JasperFx.Core; -using Lamar.IoC.Frames; -using Lamar.IoC.Resolvers; -using Lamar.Util; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using JasperFx.Core; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; +using Lamar.IoC.Resolvers; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public abstract class GeneratedInstance : Instance { - public abstract class GeneratedInstance : Instance + private readonly object _locker = new(); + protected Func _resolver; + + protected GeneratedInstance(Type serviceType, Type implementationType, ServiceLifetime lifetime) : base(serviceType, + implementationType, lifetime) { - protected GeneratedInstance(Type serviceType, Type implementationType, ServiceLifetime lifetime) : base(serviceType, implementationType, lifetime) - { - } + } - internal (string, string) GenerateResolverClassCode(GeneratedAssembly generatedAssembly) + public Type ResolverBaseType + { + get { - var typeName = GetResolverTypeName(); + switch (Lifetime) + { + case ServiceLifetime.Scoped: + return typeof(ScopedResolver<>); + case ServiceLifetime.Singleton: + return typeof(SingletonResolver<>); - var resolverType = generatedAssembly.AddType(typeName, ResolverBaseType.MakeGenericType(ServiceType)); + case ServiceLifetime.Transient: + return typeof(TransientResolver<>); + } - var method = resolverType.MethodFor("Build"); + return null; + } + } - var frame = CreateBuildFrame(); + internal (string, string) GenerateResolverClassCode(GeneratedAssembly generatedAssembly) + { + var typeName = GetResolverTypeName(); - method.Frames.Add(frame); - return (typeName, generatedAssembly.GenerateCode()); - } + var resolverType = generatedAssembly.AddType(typeName, ResolverBaseType.MakeGenericType(ServiceType)); - public string GetResolverTypeName() - { - var typeName = (ServiceType.FullNameInCode() + "_" + Name).Sanitize(); - return typeName; - } + var method = resolverType.MethodFor("Build"); - protected virtual IEnumerable relatedAssemblies() - { - yield return ServiceType.Assembly; - yield return ImplementationType.Assembly; - } + var frame = CreateBuildFrame(); + method.Frames.Add(frame); - public sealed override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - if (Lifetime == ServiceLifetime.Singleton) - { - if (mode == BuildMode.Build) - { - return generateVariableForBuilding(variables, mode, isRoot); - } + return (typeName, generatedAssembly.GenerateCode()); + } + + public string GetResolverTypeName() + { + var typeName = (ServiceType.FullNameInCode() + "_" + Name).Sanitize(); + return typeName; + } + + protected virtual IEnumerable relatedAssemblies() + { + yield return ServiceType.Assembly; + yield return ImplementationType.Assembly; + } - return new InjectedServiceField(this); - } - if (Lifetime == ServiceLifetime.Scoped && mode == BuildMode.Dependency) + public sealed override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + if (Lifetime == ServiceLifetime.Singleton) + { + if (mode == BuildMode.Build) { - return new GetInstanceFrame(this).Variable; + return generateVariableForBuilding(variables, mode, isRoot); } - return generateVariableForBuilding(variables, mode, isRoot); + return new InjectedServiceField(this); } - public Func BuildFuncResolver(Scope scope) + if (Lifetime == ServiceLifetime.Scoped && mode == BuildMode.Dependency) { - var root = scope.Root; - var def = new FuncResolverDefinition(this, root); - var resolver = def.BuildResolver(); + return new GetInstanceFrame(this).Variable; + } - switch (Lifetime) + return generateVariableForBuilding(variables, mode, isRoot); + } + + public Func BuildFuncResolver(Scope scope) + { + var root = scope.Root; + var def = new FuncResolverDefinition(this, root); + var resolver = def.BuildResolver(); + + switch (Lifetime) + { + case ServiceLifetime.Scoped: { - case ServiceLifetime.Scoped: + var locker = new object(); + + return s => { - var locker = new object(); - - return s => + if (s.Services.TryFind(Hash, out var service)) + { + return service; + } + + lock (locker) { - if (s.Services.TryFind(Hash, out object service)) + if (s.Services.TryFind(Hash, out service)) { return service; } - lock (locker) - { - if (s.Services.TryFind(Hash, out service)) - { - return service; - } + service = resolver(s); - service = resolver(s); + s.Services = s.Services.AddOrUpdate(Hash, service); - s.Services = s.Services.AddOrUpdate(Hash, service); + return service; + } + }; + } - return service; - } - + case ServiceLifetime.Singleton: + { + var locker = new object(); - }; - } - - case ServiceLifetime.Singleton: + return s => { - var locker = new object(); - - return s => + if (root.Services.TryFind(Hash, out var service)) { - if (root.Services.TryFind(Hash, out object service)) - { - return service; - } + return service; + } - lock (locker) + lock (locker) + { + if (root.Services.TryFind(Hash, out service)) { - if (root.Services.TryFind(Hash, out service)) - { - return service; - } - - service = resolver(root); - root.Services = root.Services.AddOrUpdate(Hash, service); - return service; } - - - }; - } - default: - return resolver; - } - } - public abstract Frame CreateBuildFrame(); - protected abstract Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot); + service = resolver(root); + root.Services = root.Services.AddOrUpdate(Hash, service); - private readonly object _locker = new object(); - protected Func _resolver; - - - public override Func ToResolver(Scope topScope) - { - if (_resolver == null) - { - lock (_locker) - { - if (_resolver == null) - { - buildResolver(topScope); + return service; } - } + }; } - - return _resolver; + default: + return resolver; } + } + + public abstract Frame CreateBuildFrame(); + protected abstract Variable generateVariableForBuilding(ResolverVariables variables, BuildMode mode, bool isRoot); - public override object Resolve(Scope scope) + + public override Func ToResolver(Scope topScope) + { + if (_resolver == null) { - if (_resolver != null) return _resolver(scope); - lock (_locker) { if (_resolver == null) { - buildResolver(scope); + buildResolver(topScope); } } + } + return _resolver; + } + public override object Resolve(Scope scope) + { + if (_resolver != null) + { return _resolver(scope); } - private void buildResolver(Scope scope) + lock (_locker) { - if (_resolver != null) return; - - lock (_locker) + if (_resolver == null) { - if (_resolver != null) return; - - if (ErrorMessages.Any() || Dependencies.Any(x => x.ErrorMessages.Any())) - { - var errorResolver = new ErrorMessageResolver(this); - _resolver = errorResolver.Resolve; - - } - else - { - _resolver = BuildFuncResolver(scope); - } + buildResolver(scope); } + } + return _resolver(scope); + } + private void buildResolver(Scope scope) + { + if (_resolver != null) + { + return; } - internal override string GetBuildPlan(Scope rootScope) + lock (_locker) { - if (ErrorMessages.Any()) + if (_resolver != null) { - return "Errors!" + Environment.NewLine + ErrorMessages.Join(Environment.NewLine); + return; } - - var (name, code) = GenerateResolverClassCode(rootScope.ServiceGraph.ToGeneratedAssembly()); - return code; + if (ErrorMessages.Any() || Dependencies.Any(x => x.ErrorMessages.Any())) + { + var errorResolver = new ErrorMessageResolver(this); + _resolver = errorResolver.Resolve; + } + else + { + _resolver = BuildFuncResolver(scope); + } } + } - public Type ResolverBaseType + internal override string GetBuildPlan(Scope rootScope) + { + if (ErrorMessages.Any()) { - get - { - switch (Lifetime) - { - case ServiceLifetime.Scoped: - return typeof(ScopedResolver<>); - - case ServiceLifetime.Singleton: - return typeof(SingletonResolver<>); - - case ServiceLifetime.Transient: - return typeof(TransientResolver<>); - } - - return null; - } + return "Errors!" + Environment.NewLine + ErrorMessages.Join(Environment.NewLine); } + var (name, code) = GenerateResolverClassCode(rootScope.ServiceGraph.ToGeneratedAssembly()); + return code; } - -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/GenericsPluginGraph.cs b/src/Lamar/IoC/Instances/GenericsPluginGraph.cs index 64fde955..ba070abc 100644 --- a/src/Lamar/IoC/Instances/GenericsPluginGraph.cs +++ b/src/Lamar/IoC/Instances/GenericsPluginGraph.cs @@ -1,63 +1,66 @@ using System; using System.Reflection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public static class GenericsPluginGraph { - public static class GenericsPluginGraph + public static bool CanBeCast(Type serviceType, Type implementationType) { - public static bool CanBeCast(Type serviceType, Type implementationType) + try { - try - { - return checkGenericType(implementationType, serviceType); - } - catch (Exception e) - { - var message = - string.Format("Could not Determine Whether Type '{0}' plugs into Type '{1}'", - serviceType.Name, - implementationType.Name); - throw new ArgumentException(message, e); - } + return checkGenericType(implementationType, serviceType); + } + catch (Exception e) + { + var message = + string.Format("Could not Determine Whether Type '{0}' plugs into Type '{1}'", + serviceType.Name, + implementationType.Name); + throw new ArgumentException(message, e); + } + } + + private static bool checkGenericType(Type pluggedType, Type pluginType) + { + if (pluggedType == null || pluginType == null) + { + return false; } - private static bool checkGenericType(Type pluggedType, Type pluginType) + if (pluginType.GetTypeInfo().IsAssignableFrom(pluggedType.GetTypeInfo())) { - if (pluggedType == null || pluginType == null) return false; + return true; + } - if (pluginType.GetTypeInfo().IsAssignableFrom(pluggedType.GetTypeInfo())) return true; + // check interfaces + foreach (var type in pluggedType.GetInterfaces()) + { + if (!type.GetTypeInfo().IsGenericType) + { + continue; + } -// check interfaces - foreach (var type in pluggedType.GetInterfaces()) + if (type.GetGenericTypeDefinition() == pluginType) { - if (!type.GetTypeInfo().IsGenericType) - { - continue; - } - - if (type.GetGenericTypeDefinition() == pluginType) - { - return true; - } + return true; } + } + + var baseType = pluggedType.GetTypeInfo().BaseType; + if (baseType != null && baseType.GetTypeInfo().IsGenericType) + { + var baseTypeGenericDefinition = baseType.GetGenericTypeDefinition(); - var baseType = pluggedType.GetTypeInfo().BaseType; - if (baseType != null && baseType.GetTypeInfo().IsGenericType) + if (baseTypeGenericDefinition == pluginType) { - var baseTypeGenericDefinition = baseType.GetGenericTypeDefinition(); - - if (baseTypeGenericDefinition == pluginType) - { - return true; - } - else - { - return CanBeCast(pluginType, baseTypeGenericDefinition); - } + return true; } - return false; + return CanBeCast(pluginType, baseTypeGenericDefinition); } + + return false; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/IConfiguredInstance.cs b/src/Lamar/IoC/Instances/IConfiguredInstance.cs index f13e6d8d..4dec176d 100644 --- a/src/Lamar/IoC/Instances/IConfiguredInstance.cs +++ b/src/Lamar/IoC/Instances/IConfiguredInstance.cs @@ -3,55 +3,56 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +#region sample_IConfiguredInstance + +public interface IConfiguredInstance { - #region sample_IConfiguredInstance - public interface IConfiguredInstance - { - /// - /// The constructor function that this registration is going to use to - /// construct the object - /// - ConstructorInfo Constructor { get; set; } - - /// - /// The service type that you can request. This would normally be an interface or other - /// abstraction - /// - Type ServiceType { get; } - - /// - /// The actual, concrete type - /// - Type ImplementationType { get; } - - - ServiceLifetime Lifetime { get; set; } - - /// - /// The instance name for requesting this object by name - /// - string Name { get; set; } - - /// - /// Inline definition of a constructor dependency. Select the constructor argument by type and constructor name. - /// Use this method if there is more than one constructor arguments of the same type - /// - /// - /// - /// - DependencyExpression Ctor(string constructorArg = null); - - /// - /// Directly add or interrogate the inline dependencies for this instance - /// - IReadOnlyList InlineDependencies { get; } - - /// - /// Adds an inline dependency - /// - /// - void AddInline(Instance instance); - } - #endregion -} \ No newline at end of file + /// + /// The constructor function that this registration is going to use to + /// construct the object + /// + ConstructorInfo Constructor { get; set; } + + /// + /// The service type that you can request. This would normally be an interface or other + /// abstraction + /// + Type ServiceType { get; } + + /// + /// The actual, concrete type + /// + Type ImplementationType { get; } + + + ServiceLifetime Lifetime { get; set; } + + /// + /// The instance name for requesting this object by name + /// + string Name { get; set; } + + /// + /// Directly add or interrogate the inline dependencies for this instance + /// + IReadOnlyList InlineDependencies { get; } + + /// + /// Inline definition of a constructor dependency. Select the constructor argument by type and constructor name. + /// Use this method if there is more than one constructor arguments of the same type + /// + /// + /// + /// + DependencyExpression Ctor(string constructorArg = null); + + /// + /// Adds an inline dependency + /// + /// + void AddInline(Instance instance); +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/InjectedInstance.cs b/src/Lamar/IoC/Instances/InjectedInstance.cs index 6c90436e..7a543c1d 100644 --- a/src/Lamar/IoC/Instances/InjectedInstance.cs +++ b/src/Lamar/IoC/Instances/InjectedInstance.cs @@ -2,79 +2,79 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; -using Lamar.IoC.Frames; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class InjectedInstance : Instance { - public class InjectedInstance : Instance + public InjectedInstance() : base(typeof(T), typeof(T), ServiceLifetime.Scoped) { - public InjectedInstance() : base(typeof(T), typeof(T), ServiceLifetime.Scoped) - { - Name = "Injected_" + DefaultArgName(); - } + Name = "Injected_" + DefaultArgName(); + } - public override Func ToResolver(Scope topScope) - { - return s => s.GetInjected(); - } + public override Func ToResolver(Scope topScope) + { + return s => s.GetInjected(); + } - public override object Resolve(Scope scope) - { - return scope.GetInjected(); - } + public override object Resolve(Scope scope) + { + return scope.GetInjected(); + } + + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new GetInjectedServiceFrame(this).Variable; + } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + public class GetInjectedServiceFrame : SyncFrame, IResolverFrame + { + private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.GetInjected)); + + private Variable _scope; + + public GetInjectedServiceFrame(InjectedInstance parent) { - return new GetInjectedServiceFrame(this).Variable; + Variable = new ServiceVariable(parent, this); } - - public class GetInjectedServiceFrame : SyncFrame, IResolverFrame + + public Variable Variable { get; } + + public void WriteExpressions(LambdaDefinition definition) { - private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.GetInjected)); - - private Variable _scope; + var scope = definition.Scope(); + var closedMethod = _openMethod.MakeGenericMethod(Variable.VariableType); + var expr = definition.ExpressionFor(Variable); - public GetInjectedServiceFrame(InjectedInstance parent) - { - Variable = new ServiceVariable(parent, this); - } - - public Variable Variable { get; } + var call = Expression.Call(scope, closedMethod); + var assign = Expression.Assign(expr, call); - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInjected)}<{typeof(T).FullNameInCode()}>();"); - Next?.GenerateCode(method, writer); - } + definition.Body.Add(assign); - public override IEnumerable FindVariables(IMethodVariables chain) + if (Next == null) { - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; + definition.Body.Add(expr); } + } - public void WriteExpressions(LambdaDefinition definition) - { - var scope = definition.Scope(); - var closedMethod = _openMethod.MakeGenericMethod(Variable.VariableType); - var expr = definition.ExpressionFor(Variable); - - var call = Expression.Call(scope, closedMethod); - var assign = Expression.Assign(expr, call); - - definition.Body.Add(assign); + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = {_scope.Usage}.{nameof(Scope.GetInjected)}<{typeof(T).FullNameInCode()}>();"); + Next?.GenerateCode(method, writer); + } - if (Next == null) - { - definition.Body.Add(expr); - } - } + public override IEnumerable FindVariables(IMethodVariables chain) + { + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; } } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/InlineLambdaCreationFrame.cs b/src/Lamar/IoC/Instances/InlineLambdaCreationFrame.cs index 0a0d2693..f44e0c74 100644 --- a/src/Lamar/IoC/Instances/InlineLambdaCreationFrame.cs +++ b/src/Lamar/IoC/Instances/InlineLambdaCreationFrame.cs @@ -1,70 +1,70 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Expressions; -using Lamar.IoC.Frames; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; + +namespace Lamar.IoC.Instances; -namespace Lamar.IoC.Instances +public class InlineLambdaCreationFrame : SyncFrame, IResolverFrame { - public class InlineLambdaCreationFrame : SyncFrame, IResolverFrame + private readonly Setter _setter; + + private Variable _scope; + + + public InlineLambdaCreationFrame(Setter setter, Instance instance) { - - private Variable _scope; - private readonly Setter _setter; - + Variable = new ServiceVariable(instance, this); + _setter = setter; + } - public InlineLambdaCreationFrame(Setter setter, Instance instance) - { - Variable = new ServiceVariable(instance, this); - _setter = setter; - } - - public ServiceVariable Variable { get; } + public ServiceVariable Variable { get; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}){_setter.Usage}(({typeof(TContainer).FullNameInCode()}){_scope.Usage});"); + public void WriteExpressions(LambdaDefinition definition) + { + var scope = definition.Scope(); + var variableExpr = Expression.Variable(Variable.VariableType, Variable.Usage); + definition.RegisterExpression(Variable, variableExpr); - if(!Variable.VariableType.IsPrimitive && !Variable.VariableType.IsEnum && Variable.VariableType != typeof(string)) - { - writer.WriteLine($"{_scope.Usage}.{nameof(Scope.TryAddDisposable)}({Variable.Usage});"); - } + var invokeMethod = _setter.InitialValue.GetType().GetMethod("Invoke"); + var invoke = Expression.Call(Expression.Constant(_setter.InitialValue), invokeMethod, scope); - Next?.GenerateCode(method, writer); + Expression cast = invoke; + if (!variableExpr.Type.IsAssignableFrom(invoke.Type)) + { + cast = Expression.Convert(invoke, variableExpr.Type); } - public override IEnumerable FindVariables(IMethodVariables chain) + definition.Body.Add(Expression.Assign(variableExpr, cast)); + + if (!Variable.VariableType.IsValueType) { - yield return _setter; - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; + definition.TryRegisterDisposable(variableExpr); } + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}){_setter.Usage}(({typeof(TContainer).FullNameInCode()}){_scope.Usage});"); - public void WriteExpressions(LambdaDefinition definition) + if (!Variable.VariableType.IsPrimitive && !Variable.VariableType.IsEnum && + Variable.VariableType != typeof(string)) { - var scope = definition.Scope(); - var variableExpr = Expression.Variable(Variable.VariableType, Variable.Usage); - definition.RegisterExpression(Variable, variableExpr); + writer.WriteLine($"{_scope.Usage}.{nameof(Scope.TryAddDisposable)}({Variable.Usage});"); + } - var invokeMethod = _setter.InitialValue.GetType().GetMethod("Invoke"); - var invoke = Expression.Call(Expression.Constant(_setter.InitialValue), invokeMethod, scope); + Next?.GenerateCode(method, writer); + } - Expression cast = invoke; - if (!variableExpr.Type.IsAssignableFrom(invoke.Type)) - { - cast = Expression.Convert(invoke, variableExpr.Type); - } - - definition.Body.Add(Expression.Assign(variableExpr, cast)); - - if (!Variable.VariableType.IsValueType) - { - definition.TryRegisterDisposable(variableExpr); - } - } + public override IEnumerable FindVariables(IMethodVariables chain) + { + yield return _setter; + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/Instance.cs b/src/Lamar/IoC/Instances/Instance.cs index 51ab97fe..2430fc5e 100644 --- a/src/Lamar/IoC/Instances/Instance.cs +++ b/src/Lamar/IoC/Instances/Instance.cs @@ -2,334 +2,354 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using JasperFx.CodeGeneration.Model; using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.IoC.Frames; -using Lamar.Util; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; +namespace Lamar.IoC.Instances; -namespace Lamar.IoC.Instances +public abstract class Instance { - public abstract class Instance - { - public abstract Func ToResolver(Scope topScope); - - public bool IsOnlyOneOfServiceType { get; set; } + public readonly IList ErrorMessages = new List(); + private string _name = "default"; - public bool IsExplicitlyNamed { get; set; } - - public ServiceDescriptor ToDescriptor() + protected Instance(Type serviceType, Type implementationType, ServiceLifetime lifetime) + { + if (!CanBeCastTo(implementationType, serviceType)) { - return new ServiceDescriptor(ServiceType, this); + throw new ArgumentOutOfRangeException(nameof(implementationType), + $"{implementationType.FullNameInCode()} cannot be cast to {serviceType.FullNameInCode()}"); } - - public string DefaultArgName() - { - var argName = Variable.DefaultArgName(ServiceType); - if (ServiceType.IsGenericType) - { - argName += "_of_" + ServiceType.GetGenericArguments().Select(t => t.NameInCode().Sanitize()).Join("_"); - } - - return IsOnlyOneOfServiceType ? argName : argName + HashCode(ServiceType, Name).ToString().Replace("-", "_"); - } + ServiceType = serviceType; + Lifetime = lifetime; + ImplementationType = implementationType; + Name = "default"; + } - internal IEnumerable ReferencedAssemblies() - { - yield return ServiceType.Assembly; - yield return ImplementationType.Assembly; + public bool IsOnlyOneOfServiceType { get; set; } - if (ServiceType.IsGenericType) - { - foreach (var type in ServiceType.GetGenericArguments()) - { - yield return type.Assembly; - } - } + public bool IsExplicitlyNamed { get; set; } - if (ImplementationType.IsGenericType) - { - foreach (var type in ImplementationType.GetGenericArguments()) - { - yield return type.Assembly; - } - } - } + public Type ServiceType { get; } + public Type ImplementationType { get; } - public Type ServiceType { get; } - public Type ImplementationType { get; } + public int Hash { get; set; } - public static Instance For(ServiceDescriptor service) + public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Transient; + + public string Name + { + get => _name; + set { - if (service.ImplementationInstance is Instance instance) return instance; + _name = value; + Hash = GetHashCode(); + } + } - if (service.ImplementationInstance != null) return new ObjectInstance(service.ServiceType, service.ImplementationInstance); + internal bool InlineIsLimitedToExactNameMatch { get; set; } - if (service.ImplementationFactory != null) return new LambdaInstance(service.ServiceType, service.ImplementationFactory, service.Lifetime); + public bool HasPlanned { get; protected internal set; } - return new ConstructorInstance(service.ServiceType, service.ImplementationType, service.Lifetime); - } + public bool PlanningSucceeded { get; protected internal set; } - public static bool CanBeCastTo(Type implementationType, Type serviceType) - { - if (implementationType == null) return false; + public Instance[] ImmediateDependencies { get; private set; } - if (implementationType == serviceType) return true; + public Instance[] Dependencies { get; protected set; } = new Instance[0]; - if (serviceType.IsOpenGeneric()) - { - return GenericsPluginGraph.CanBeCast(serviceType, implementationType); - } + public bool IsDefault { get; set; } = false; - if (implementationType.IsOpenGeneric()) - { - return false; - } + /// + /// Only used to track naming within inline dependencies + /// + internal Instance Parent { get; set; } + public abstract Func ToResolver(Scope topScope); - return serviceType.GetTypeInfo().IsAssignableFrom(implementationType.GetTypeInfo()); - } + public ServiceDescriptor ToDescriptor() + { + return new ServiceDescriptor(ServiceType, this); + } + + public string DefaultArgName() + { + var argName = Variable.DefaultArgName(ServiceType); - protected Instance(Type serviceType, Type implementationType, ServiceLifetime lifetime) + if (ServiceType.IsGenericType) { - if (!CanBeCastTo(implementationType, serviceType)) - { - throw new ArgumentOutOfRangeException(nameof(implementationType), $"{implementationType.FullNameInCode()} cannot be cast to {serviceType.FullNameInCode()}"); - } + argName += "_of_" + ServiceType.GetGenericArguments().Select(t => t.NameInCode().Sanitize()).Join("_"); + } + + return IsOnlyOneOfServiceType ? argName : argName + HashCode(ServiceType, Name).ToString().Replace("-", "_"); + } - ServiceType = serviceType; - Lifetime = lifetime; - ImplementationType = implementationType; - Name = "default"; + internal IEnumerable ReferencedAssemblies() + { + yield return ServiceType.Assembly; + yield return ImplementationType.Assembly; + if (ServiceType.IsGenericType) + { + foreach (var type in ServiceType.GetGenericArguments()) yield return type.Assembly; } - public abstract object Resolve(Scope scope); - - /// - /// Resolve the service as if it were only going to ever be resolved once - /// - /// - /// - public virtual object QuickResolve(Scope scope) + if (ImplementationType.IsGenericType) { - return Resolve(scope); + foreach (var type in ImplementationType.GetGenericArguments()) yield return type.Assembly; } + } - public int Hash { get; set; } + public static Instance For(ServiceDescriptor service) + { + if (service.ImplementationInstance is Instance instance) + { + return instance; + } - public virtual string WhyRequireServiceProvider(IMethodVariables method) + if (service.ImplementationInstance != null) { - var text = ""; - foreach (var dependency in Dependencies) - { - if (dependency.RequiresServiceProvider(method)) - { - text += Environment.NewLine; - text += "Dependency: " + dependency.ToString() + Environment.NewLine; - text += dependency.WhyRequireServiceProvider(method); - text += Environment.NewLine; - } - } + return new ObjectInstance(service.ServiceType, service.ImplementationInstance); + } - return text; + if (service.ImplementationFactory != null) + { + return new LambdaInstance(service.ServiceType, service.ImplementationFactory, service.Lifetime); } - public virtual bool RequiresServiceProvider(IMethodVariables method) + return new ConstructorInstance(service.ServiceType, service.ImplementationType, service.Lifetime); + } + + public static bool CanBeCastTo(Type implementationType, Type serviceType) + { + if (implementationType == null) { - if (Lifetime == ServiceLifetime.Singleton) return false; - - foreach (var dependency in ImmediateDependencies) - { - // Always no if a singleton - if (dependency.Lifetime == ServiceLifetime.Singleton) continue; + return false; + } - if (dependency.ServiceType == typeof(IContainer) || - dependency.ServiceType == typeof(IServiceProvider)) return true; + if (implementationType == serviceType) + { + return true; + } - // This is for variables that might be created outside of the container - if (method.TryFindVariable(dependency.ServiceType, VariableSource.NotServices) != null) continue; - if (dependency.RequiresServiceProvider(method)) return true; - } + if (serviceType.IsOpenGeneric()) + { + return GenericsPluginGraph.CanBeCast(serviceType, implementationType); + } + if (implementationType.IsOpenGeneric()) + { return false; } - public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Transient; - public string Name + return serviceType.GetTypeInfo().IsAssignableFrom(implementationType.GetTypeInfo()); + } + + public abstract object Resolve(Scope scope); + + /// + /// Resolve the service as if it were only going to ever be resolved once + /// + /// + /// + public virtual object QuickResolve(Scope scope) + { + return Resolve(scope); + } + + public virtual string WhyRequireServiceProvider(IMethodVariables method) + { + var text = ""; + foreach (var dependency in Dependencies) { - get => _name; - set + if (dependency.RequiresServiceProvider(method)) { - _name = value; - Hash = GetHashCode(); + text += Environment.NewLine; + text += "Dependency: " + dependency + Environment.NewLine; + text += dependency.WhyRequireServiceProvider(method); + text += Environment.NewLine; } } - - internal bool InlineIsLimitedToExactNameMatch { get; set; } - public bool HasPlanned { get; protected internal set; } - - public bool PlanningSucceeded { get; protected internal set; } + return text; + } - public void CreatePlan(ServiceGraph services) + public virtual bool RequiresServiceProvider(IMethodVariables method) + { + if (Lifetime == ServiceLifetime.Singleton) { - if (HasPlanned) return; + return false; + } - try + foreach (var dependency in ImmediateDependencies) + { + // Always no if a singleton + if (dependency.Lifetime == ServiceLifetime.Singleton) { - services.StartingToPlan(this); + continue; } - catch (Exception e) + + if (dependency.ServiceType == typeof(IContainer) || + dependency.ServiceType == typeof(IServiceProvider)) { - ErrorMessages.Add(e.Message); + return true; + } - services.FinishedPlanning(); - HasPlanned = true; - return; + // This is for variables that might be created outside of the container + if (method.TryFindVariable(dependency.ServiceType, VariableSource.NotServices) != null) + { + continue; } - // Can't do the planning on open generic types 'cause bad stuff happens - if (!ServiceType.IsOpenGeneric()) + if (dependency.RequiresServiceProvider(method)) { - foreach (var policy in services.InstancePolicies) - { - policy.Apply(this); - } + return true; + } + } - var atts = ImplementationType.GetAllAttributes(); - foreach (var att in atts) - { - att.Alter(this); - if (this is IConfiguredInstance) - { - att.Alter(this.As()); - } - } - - var dependencies = createPlan(services) ?? Enumerable.Empty(); + return false; + } - ImmediateDependencies = dependencies.ToArray(); + public void CreatePlan(ServiceGraph services) + { + if (HasPlanned) + { + return; + } + + try + { + services.StartingToPlan(this); + } + catch (Exception e) + { + ErrorMessages.Add(e.Message); + + services.FinishedPlanning(); + HasPlanned = true; + return; + } - if (ImmediateDependencies.Any(x => x.Dependencies.Contains(this))) + // Can't do the planning on open generic types 'cause bad stuff happens + if (!ServiceType.IsOpenGeneric()) + { + foreach (var policy in services.InstancePolicies) policy.Apply(this); + + var atts = ImplementationType.GetAllAttributes(); + foreach (var att in atts) + { + att.Alter(this); + if (this is IConfiguredInstance) { - throw new InvalidOperationException("Bi-directional dependencies detected to " + ToString()); + att.Alter(this.As()); } - - Dependencies = ImmediateDependencies.Concat(ImmediateDependencies.SelectMany(x => x.Dependencies)).Distinct().ToArray(); } - services.ClearPlanning(); + var dependencies = createPlan(services) ?? Enumerable.Empty(); - PlanningSucceeded = ErrorMessages.Count == 0; - HasPlanned = true; - } + ImmediateDependencies = dependencies.ToArray(); - public Instance[] ImmediateDependencies { get; private set; } + if (ImmediateDependencies.Any(x => x.Dependencies.Contains(this))) + { + throw new InvalidOperationException("Bi-directional dependencies detected to " + ToString()); + } - public virtual void Reset() - { - HasPlanned = false; - PlanningSucceeded = false; - ErrorMessages.Clear(); + Dependencies = ImmediateDependencies.Concat(ImmediateDependencies.SelectMany(x => x.Dependencies)) + .Distinct().ToArray(); } + services.ClearPlanning(); - public abstract Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot); + PlanningSucceeded = ErrorMessages.Count == 0; + HasPlanned = true; + } - public virtual Variable CreateInlineVariable(ResolverVariables variables) - { - return CreateVariable(BuildMode.Dependency, variables, false); - } - - protected virtual IEnumerable createPlan(ServiceGraph services) - { - return Enumerable.Empty(); - } + public virtual void Reset() + { + HasPlanned = false; + PlanningSucceeded = false; + ErrorMessages.Clear(); + } - public readonly IList ErrorMessages = new List(); - private string _name = "default"; + public abstract Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot); - public Instance[] Dependencies { get; protected set; } = new Instance[0]; + public virtual Variable CreateInlineVariable(ResolverVariables variables) + { + return CreateVariable(BuildMode.Dependency, variables, false); + } - /// - /// Is this instance known to be dependent upon the dependencyType? - /// - /// - /// - public bool DependsOn(Type dependencyType) - { - return Dependencies.Any(x => x.ServiceType == dependencyType || x.ImplementationType == dependencyType); - } + protected virtual IEnumerable createPlan(ServiceGraph services) + { + return Enumerable.Empty(); + } - public bool IsDefault { get; set; } = false; + /// + /// Is this instance known to be dependent upon the dependencyType? + /// + /// + /// + public bool DependsOn(Type dependencyType) + { + return Dependencies.Any(x => x.ServiceType == dependencyType || x.ImplementationType == dependencyType); + } - protected bool tryGetService(Scope scope, out object service) - { - return scope.Services.TryFind(Hash, out service); - } + protected bool tryGetService(Scope scope, out object service) + { + return scope.Services.TryFind(Hash, out service); + } - protected void store(Scope scope, object service) - { - scope.Services = scope.Services.AddOrUpdate(Hash, service); - } + protected void store(Scope scope, object service) + { + scope.Services = scope.Services.AddOrUpdate(Hash, service); + } - /// - /// Tries to describe how this instance would be resolved at runtime - /// - /// - internal virtual string GetBuildPlan(Scope rootScope) => ToString(); + /// + /// Tries to describe how this instance would be resolved at runtime + /// + /// + internal virtual string GetBuildPlan(Scope rootScope) + { + return ToString(); + } - public sealed override int GetHashCode() - { - unchecked - { - return HashCode(ServiceType, Name); - } - } + public sealed override int GetHashCode() + { + return HashCode(ServiceType, Name); + } - public static int HashCode(Type serviceType, string name = null) - { - return (serviceType.GetHashCode() * 397) ^ (name ?? "default").GetHashCode(); - } + public static int HashCode(Type serviceType, string name = null) + { + return (serviceType.GetHashCode() * 397) ^ (name ?? "default").GetHashCode(); + } - public virtual Instance CloseType(Type serviceType, Type[] templateTypes) - { - return null; - } - - /// - /// Only used to track naming within inline dependencies - /// - internal Instance Parent { get; set; } + public virtual Instance CloseType(Type serviceType, Type[] templateTypes) + { + return null; + } - public bool IsInlineDependency() - { - return Parent != null; - } + public bool IsInlineDependency() + { + return Parent != null; + } - protected string inlineSetterName() + protected string inlineSetterName() + { + var name = Name; + var parent = Parent; + while (parent != null) { - var name = Name; - var parent = Parent; - while (parent != null) - { - name = parent.Name + "_" + name; - parent = parent.Parent; - } - - return "func_" + name.Sanitize(); + name = parent.Name + "_" + name; + parent = parent.Parent; } + + return "func_" + name.Sanitize(); } -} +} \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/LambdaDefinitionExtensions.cs b/src/Lamar/IoC/Instances/LambdaDefinitionExtensions.cs index 9c41aeed..2bb1213c 100644 --- a/src/Lamar/IoC/Instances/LambdaDefinitionExtensions.cs +++ b/src/Lamar/IoC/Instances/LambdaDefinitionExtensions.cs @@ -1,43 +1,38 @@ using System; -using System.Collections.Concurrent; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using JasperFx.Core.Reflection; using JasperFx.CodeGeneration.Expressions; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public static class LambdaDefinitionExtensions { - public static class LambdaDefinitionExtensions + private static readonly MethodInfo _tryRegisterDisposable = + ReflectionHelper.GetMethod(x => x.TryAddDisposable(null)); + + public static void RegisterDisposable(this LambdaDefinition definition, Expression parameter, + Type variableType) + { + var scope = definition.Arguments.Single(); + + var call = Expression.Call(scope, _tryRegisterDisposable, parameter); + + definition.Body.Add(call); + } + + public static void TryRegisterDisposable(this LambdaDefinition definition, Expression parameter) + { + var scope = definition.Arguments.Single(); + + var call = Expression.Call(scope, _tryRegisterDisposable, parameter); + + definition.Body.Add(call); + } + + public static Expression Scope(this LambdaDefinition definition) { - private static readonly MethodInfo _tryRegisterDisposable = - ReflectionHelper.GetMethod(x => x.TryAddDisposable(null)); - - public static void RegisterDisposable(this LambdaDefinition definition, Expression parameter, - Type variableType) - { - var scope = definition.Arguments.Single(); - - var @call = Expression.Call(scope, _tryRegisterDisposable, parameter); - - definition.Body.Add(@call); - } - - public static void TryRegisterDisposable(this LambdaDefinition definition, Expression parameter) - { - var scope = definition.Arguments.Single(); - - var @call = Expression.Call(scope, _tryRegisterDisposable, parameter); - - definition.Body.Add(@call); - } - - public static Expression Scope(this LambdaDefinition definition) - { - return definition.Arguments.Single(); - } + return definition.Arguments.Single(); } - - } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/LambdaInstance.cs b/src/Lamar/IoC/Instances/LambdaInstance.cs index 18563071..4c3f5c32 100644 --- a/src/Lamar/IoC/Instances/LambdaInstance.cs +++ b/src/Lamar/IoC/Instances/LambdaInstance.cs @@ -1,140 +1,144 @@ using System; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class LambdaInstance : LambdaInstance { - public class LambdaInstance : LambdaInstance + public LambdaInstance(Type serviceType, Func factory, ServiceLifetime lifetime) : base( + serviceType, factory, lifetime) { - public LambdaInstance(Type serviceType, Func factory, ServiceLifetime lifetime) : base(serviceType, factory, lifetime) - { - } + } - public static LambdaInstance For(Func func) - { - return new LambdaInstance(typeof(TReturn), func, ServiceLifetime.Transient); - } - - public static LambdaInstance For(Func factory, - ServiceLifetime lifetime = ServiceLifetime.Transient) - { - return new LambdaInstance(typeof(T), s => factory(s), lifetime); - } + public static LambdaInstance For(Func func) + { + return new LambdaInstance(typeof(TReturn), func, ServiceLifetime.Transient); } - - public class LambdaInstance : Instance + + public static LambdaInstance For(Func factory, + ServiceLifetime lifetime = ServiceLifetime.Transient) { - public Func Factory { get; } + return new LambdaInstance(typeof(T), s => factory(s), lifetime); + } +} - public LambdaInstance(Type serviceType, Func factory, ServiceLifetime lifetime) : - base(serviceType, serviceType, lifetime) - { - Factory = factory; - Name = serviceType.NameInCode(); - } +public class LambdaInstance : Instance +{ + private readonly object _locker = new(); + private IResolver _resolver; - // This is important. If the lambda instance is a singleton, it's injected as a singleton - // to an object constructor and does not need the ServiceProvider - public override bool RequiresServiceProvider(IMethodVariables method) => Lifetime != ServiceLifetime.Singleton; + public LambdaInstance(Type serviceType, Func factory, ServiceLifetime lifetime) : + base(serviceType, serviceType, lifetime) + { + Factory = factory; + Name = serviceType.NameInCode(); + } - public override string WhyRequireServiceProvider(IMethodVariables method) - { - return $"The scoping is {Lifetime}, so a Lambda registration requires" + Environment.NewLine + - "the usage of a nested container for resolution for correct scoping." + Environment.NewLine + "A formal factory provider may be an alternative"; - } + public Func Factory { get; } - public string Description { get; set; } + public string Description { get; set; } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - if (Lifetime == ServiceLifetime.Singleton && mode != BuildMode.Build) - { - return new InjectedServiceField(this); - } - if (Lifetime == ServiceLifetime.Transient && mode != BuildMode.Build) - { - return CreateInlineVariable(variables); - } + // This is important. If the lambda instance is a singleton, it's injected as a singleton + // to an object constructor and does not need the ServiceProvider + public override bool RequiresServiceProvider(IMethodVariables method) + { + return Lifetime != ServiceLifetime.Singleton; + } - return new GetInstanceFrame(this).Variable; - } + public override string WhyRequireServiceProvider(IMethodVariables method) + { + return $"The scoping is {Lifetime}, so a Lambda registration requires" + Environment.NewLine + + "the usage of a nested container for resolution for correct scoping." + Environment.NewLine + + "A formal factory provider may be an alternative"; + } - public override Variable CreateInlineVariable(ResolverVariables variables) + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + if (Lifetime == ServiceLifetime.Singleton && mode != BuildMode.Build) { - var setter = new Setter(typeof(Func), inlineSetterName()) - { - InitialValue = Factory - }; + return new InjectedServiceField(this); + } - return new InlineLambdaCreationFrame(setter, this).Variable; + if (Lifetime == ServiceLifetime.Transient && mode != BuildMode.Build) + { + return CreateInlineVariable(variables); } - private IResolver _resolver; - private readonly object _locker = new object(); + return new GetInstanceFrame(this).Variable; + } - public override Func ToResolver(Scope topScope) + public override Variable CreateInlineVariable(ResolverVariables variables) + { + var setter = new Setter(typeof(Func), inlineSetterName()) { - if (_resolver == null) + InitialValue = Factory + }; + + return new InlineLambdaCreationFrame(setter, this).Variable; + } + + public override Func ToResolver(Scope topScope) + { + if (_resolver == null) + { + lock (_locker) { - lock (_locker) + if (_resolver == null) { - if (_resolver == null) - { - _resolver = buildResolver(topScope.Root); - _resolver.Hash = Hash; - _resolver.Name = Name; - } + _resolver = buildResolver(topScope.Root); + _resolver.Hash = Hash; + _resolver.Name = Name; } } - - return scope => _resolver.Resolve(scope); } - public override object Resolve(Scope scope) + return scope => _resolver.Resolve(scope); + } + + public override object Resolve(Scope scope) + { + if (_resolver == null) { - if (_resolver == null) + lock (_locker) { - lock (_locker) + if (_resolver == null) { - if (_resolver == null) - { - _resolver = buildResolver(scope.Root); - _resolver.Hash = Hash; - _resolver.Name = Name; - } + _resolver = buildResolver(scope.Root); + _resolver.Hash = Hash; + _resolver.Name = Name; } } - - return _resolver.Resolve(scope); } - protected IResolver buildResolver(Scope rootScope) + return _resolver.Resolve(scope); + } + + protected IResolver buildResolver(Scope rootScope) + { + switch (Lifetime) { - switch (Lifetime) - { - case ServiceLifetime.Transient: - return new TransientLambdaResolver(Factory); - - case ServiceLifetime.Scoped: - return new ScopedLambdaResolver(Factory); - - case ServiceLifetime.Singleton: - return new SingletonLambdaResolver(Factory, rootScope); - } + case ServiceLifetime.Transient: + return new TransientLambdaResolver(Factory); - throw new ArgumentOutOfRangeException(nameof(Lifetime)); - } - - + case ServiceLifetime.Scoped: + return new ScopedLambdaResolver(Factory); - public override string ToString() - { - return Description ?? $"Lambda Factory of {ServiceType.NameInCode()}"; + case ServiceLifetime.Singleton: + return new SingletonLambdaResolver(Factory, rootScope); } + + throw new ArgumentOutOfRangeException(nameof(Lifetime)); } -} + + + public override string ToString() + { + return Description ?? $"Lambda Factory of {ServiceType.NameInCode()}"; + } +} \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/NullInstance.cs b/src/Lamar/IoC/Instances/NullInstance.cs index 4f7aa2c2..1ef48a95 100644 --- a/src/Lamar/IoC/Instances/NullInstance.cs +++ b/src/Lamar/IoC/Instances/NullInstance.cs @@ -1,60 +1,57 @@ using System; using System.Linq.Expressions; -using Lamar.IoC.Frames; -using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class NullInstance : Instance { - public class NullInstance : Instance + public NullInstance(Type serviceType) : base(serviceType, serviceType, ServiceLifetime.Transient) { - public NullInstance(Type serviceType) : base(serviceType, serviceType, ServiceLifetime.Transient) - { - Hash = GetHashCode(); - } + Hash = GetHashCode(); + } - public override Func ToResolver(Scope topScope) - { - return s => null; - } + public override Func ToResolver(Scope topScope) + { + return s => null; + } - public override object Resolve(Scope scope) - { - return null; - } + public override object Resolve(Scope scope) + { + return null; + } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new DefaultVariable(ServiceType); - } + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new DefaultVariable(ServiceType); } +} - public class DefaultVariable : Variable +public class DefaultVariable : Variable +{ + public DefaultVariable(Type variableType) : base(variableType, $"default({variableType.FullNameInCode()})") { - public DefaultVariable(Type variableType) : base(variableType, $"default({variableType.FullNameInCode()})") - { - - } + } - public override Expression ToVariableExpression(LambdaDefinition definition) - { - return Expression.Default(VariableType); - } + public override Expression ToVariableExpression(LambdaDefinition definition) + { + return Expression.Default(VariableType); } +} - public class NullVariable : Variable +public class NullVariable : Variable +{ + public NullVariable(Type variableType) : base(variableType, "null") { - public NullVariable(Type variableType) : base(variableType, "null") - { - } + } - public override void OverrideName(string variableName) - { - // nothing - } + public override void OverrideName(string variableName) + { + // nothing } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/ObjectInstance.cs b/src/Lamar/IoC/Instances/ObjectInstance.cs index 820b5b4d..264c5b57 100644 --- a/src/Lamar/IoC/Instances/ObjectInstance.cs +++ b/src/Lamar/IoC/Instances/ObjectInstance.cs @@ -1,66 +1,64 @@ using System; -using Lamar.IoC.Frames; -using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class ObjectInstance : Instance, IDisposable { - public class ObjectInstance : Instance, IDisposable + public ObjectInstance(Type serviceType, object service) : base(serviceType, service?.GetType() ?? serviceType, + ServiceLifetime.Singleton) { - public static ObjectInstance For(T @object) - { - return new ObjectInstance(typeof(T), @object); - } - - public ObjectInstance(Type serviceType, object service) : base(serviceType, service?.GetType() ?? serviceType, ServiceLifetime.Singleton) - { - Service = service; - Name = service?.GetType().NameInCode() ?? serviceType.NameInCode(); - Hash = GetHashCode(); - } + Service = service; + Name = service?.GetType().NameInCode() ?? serviceType.NameInCode(); + Hash = GetHashCode(); + } - public object Service { get; } - - + public object Service { get; } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new InjectedServiceField(this); - } + public void Dispose() + { + (Service as IDisposable)?.Dispose(); + } - public override Func ToResolver(Scope topScope) - { - return s => Service; - } + public static ObjectInstance For(T @object) + { + return new ObjectInstance(typeof(T), @object); + } - public override object Resolve(Scope scope) - { - return Service; - } - public override object QuickResolve(Scope scope) - { - return Service; - } + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new InjectedServiceField(this); + } - public override Variable CreateInlineVariable(ResolverVariables variables) - { - return new Setter(ServiceType, inlineSetterName()) - { - InitialValue = Service - }; - } + public override Func ToResolver(Scope topScope) + { + return s => Service; + } - public void Dispose() - { - (Service as IDisposable)?.Dispose(); - } + public override object Resolve(Scope scope) + { + return Service; + } - public override string ToString() + public override object QuickResolve(Scope scope) + { + return Service; + } + + public override Variable CreateInlineVariable(ResolverVariables variables) + { + return new Setter(ServiceType, inlineSetterName()) { - return "User Supplied Object"; - } + InitialValue = Service + }; + } + + public override string ToString() + { + return "User Supplied Object"; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/ReferencedInstance.cs b/src/Lamar/IoC/Instances/ReferencedInstance.cs index dd5fe6a6..cc07a4e0 100644 --- a/src/Lamar/IoC/Instances/ReferencedInstance.cs +++ b/src/Lamar/IoC/Instances/ReferencedInstance.cs @@ -1,74 +1,80 @@ using System; using System.Collections.Generic; -using Lamar.IoC.Frames; -using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class ReferencedInstance : Instance { - public class ReferencedInstance : Instance + private readonly string _instanceKey; + private Instance _inner; + + public ReferencedInstance(Type serviceType, string instanceKey) : base(serviceType, serviceType, + ServiceLifetime.Transient) { - private readonly string _instanceKey; - private Instance _inner; + _instanceKey = instanceKey; + } - public ReferencedInstance(Type serviceType, string instanceKey) : base(serviceType, serviceType, ServiceLifetime.Transient) - { - _instanceKey = instanceKey; - } + public override Func ToResolver(Scope topScope) + { + return _inner.ToResolver(topScope); + } - public override Func ToResolver(Scope topScope) - { - return _inner.ToResolver(topScope); - } + public override object Resolve(Scope scope) + { + return _inner.Resolve(scope); + } - public override object Resolve(Scope scope) - { - return _inner.Resolve(scope); - } + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return _inner.CreateVariable(mode, variables, isRoot); + } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return _inner.CreateVariable(mode, variables, isRoot); - } + public override object QuickResolve(Scope scope) + { + return _inner.QuickResolve(scope); + } - public override object QuickResolve(Scope scope) - { - return _inner.QuickResolve(scope); - } + public override bool RequiresServiceProvider(IMethodVariables method) + { + return _inner.RequiresServiceProvider(method); + } - public override bool RequiresServiceProvider(IMethodVariables method) => _inner.RequiresServiceProvider(method); - - public override string WhyRequireServiceProvider(IMethodVariables method) - { - return _inner.WhyRequireServiceProvider(method); - } - - public override Variable CreateInlineVariable(ResolverVariables variables) + public override string WhyRequireServiceProvider(IMethodVariables method) + { + return _inner.WhyRequireServiceProvider(method); + } + + public override Variable CreateInlineVariable(ResolverVariables variables) + { + return _inner.CreateInlineVariable(variables); + } + + protected override IEnumerable createPlan(ServiceGraph services) + { + _inner = services.FindInstance(ServiceType, _instanceKey); + if (_inner == null) { - return _inner.CreateInlineVariable(variables); + throw new InvalidOperationException( + $"Referenced instance of {ServiceType.FullNameInCode()} named '{_instanceKey}' does not exist"); } - protected override IEnumerable createPlan(ServiceGraph services) - { - _inner = services.FindInstance(ServiceType, _instanceKey); - if (_inner == null) throw new InvalidOperationException($"Referenced instance of {ServiceType.FullNameInCode()} named '{_instanceKey}' does not exist"); - - _inner.Parent = Parent; - Lifetime = _inner.Lifetime; + _inner.Parent = Parent; + Lifetime = _inner.Lifetime; - yield return _inner; - } + yield return _inner; + } - internal override string GetBuildPlan(Scope rootScope) - { - return _inner.GetBuildPlan(rootScope); - } + internal override string GetBuildPlan(Scope rootScope) + { + return _inner.GetBuildPlan(rootScope); + } - public override Instance CloseType(Type serviceType, Type[] templateTypes) - { - return _inner.CloseType(serviceType, templateTypes); - } + public override Instance CloseType(Type serviceType, Type[] templateTypes) + { + return _inner.CloseType(serviceType, templateTypes); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Instances/SetterWrappedServiceVariable.cs b/src/Lamar/IoC/Instances/SetterWrappedServiceVariable.cs index 8fe1594f..eb6fc744 100644 --- a/src/Lamar/IoC/Instances/SetterWrappedServiceVariable.cs +++ b/src/Lamar/IoC/Instances/SetterWrappedServiceVariable.cs @@ -1,22 +1,22 @@ -using Lamar.IoC.Frames; -using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Frames; -namespace Lamar.IoC.Instances +namespace Lamar.IoC.Instances; + +public class SetterWrappedServiceVariable : ServiceVariable { - public class SetterWrappedServiceVariable : ServiceVariable - { - private readonly Setter _setter; + private readonly Setter _setter; - public SetterWrappedServiceVariable(Setter setter, Instance instance, Frame creator, ServiceDeclaration declaration = ServiceDeclaration.ImplementationType) : base(instance, creator, declaration) - { - _setter = setter; - } + public SetterWrappedServiceVariable(Setter setter, Instance instance, Frame creator, + ServiceDeclaration declaration = ServiceDeclaration.ImplementationType) : base(instance, creator, declaration) + { + _setter = setter; + } - public override void OverrideName(string variableName) - { - _setter.OverrideName(variableName); - base.OverrideName(variableName); - } + public override void OverrideName(string variableName) + { + _setter.OverrideName(variableName); + base.OverrideName(variableName); } } \ No newline at end of file diff --git a/src/Lamar/IoC/LamarException.cs b/src/Lamar/IoC/LamarException.cs index b426dce0..72965bfa 100644 --- a/src/Lamar/IoC/LamarException.cs +++ b/src/Lamar/IoC/LamarException.cs @@ -1,15 +1,14 @@ using System; -namespace Lamar.IoC +namespace Lamar.IoC; + +public class LamarException : Exception { - public class LamarException : Exception + public LamarException(string message) : base(message) { - public LamarException(string message) : base(message) - { - } + } - public LamarException(string message, Exception innerException) : base(message, innerException) - { - } + public LamarException(string message, Exception innerException) : base(message, innerException) + { } } \ No newline at end of file diff --git a/src/Lamar/IoC/LamarMissingRegistrationException.cs b/src/Lamar/IoC/LamarMissingRegistrationException.cs index 46d35644..23c00a75 100644 --- a/src/Lamar/IoC/LamarMissingRegistrationException.cs +++ b/src/Lamar/IoC/LamarMissingRegistrationException.cs @@ -1,21 +1,22 @@ using System; -using JasperFx.CodeGeneration; +using JasperFx.Core.Reflection; -namespace Lamar.IoC +namespace Lamar.IoC; + +public class LamarMissingRegistrationException : LamarException { - public class LamarMissingRegistrationException : LamarException + public LamarMissingRegistrationException(Type serviceType, string name) : base( + $"Unknown service registration '{name}' of {serviceType.FullNameInCode()}") { - public LamarMissingRegistrationException(Type serviceType, string name) : base($"Unknown service registration '{name}' of {serviceType.FullNameInCode()}") - { - } + } - public LamarMissingRegistrationException(Type serviceType) : base($"No service registrations exist or can be derived for {serviceType.FullNameInCode()}") - { - } + public LamarMissingRegistrationException(Type serviceType) : base( + $"No service registrations exist or can be derived for {serviceType.FullNameInCode()}") + { + } - public LamarMissingRegistrationException(ServiceFamily family) : base($"No service registrations exist for {family.ServiceType.FullNameInCode()} or can be derived because:\n{family.CannotBeResolvedMessage ?? "No registrations"}") - { - - } + public LamarMissingRegistrationException(ServiceFamily family) : base( + $"No service registrations exist for {family.ServiceType.FullNameInCode()} or can be derived because:\n{family.CannotBeResolvedMessage ?? "No registrations"}") + { } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/FuncByNameInstance.cs b/src/Lamar/IoC/Lazy/FuncByNameInstance.cs index 98bd4a82..7c072332 100644 --- a/src/Lamar/IoC/Lazy/FuncByNameInstance.cs +++ b/src/Lamar/IoC/Lazy/FuncByNameInstance.cs @@ -1,47 +1,55 @@ using System; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Lazy +namespace Lamar.IoC.Lazy; + +internal class FuncByNameInstance : Instance { - internal class FuncByNameInstance : Instance + public FuncByNameInstance() : base(typeof(Func), typeof(Func), ServiceLifetime.Transient) { - public FuncByNameInstance() : base(typeof(Func), typeof(Func), ServiceLifetime.Transient) - { - Name = "func_by_name_of_" + typeof(T).NameInCode(); - } + Name = "func_by_name_of_" + typeof(T).NameInCode(); + } - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new GetFuncByNameFrame(this, typeof(T)).Variable; - } - + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new GetFuncByNameFrame(this, typeof(T)).Variable; + } - public override bool RequiresServiceProvider(IMethodVariables method) => true; - public override string WhyRequireServiceProvider(IMethodVariables method) - { - return "Func uses Lamar scopes directly"; - } + public override bool RequiresServiceProvider(IMethodVariables method) + { + return true; + } + + public override string WhyRequireServiceProvider(IMethodVariables method) + { + return "Func uses Lamar scopes directly"; + } - public override Func ToResolver(Scope topScope) + public override Func ToResolver(Scope topScope) + { + return scope => { - return scope => + T Func(string name) { - T Func(string name) => scope.GetInstance(name); + return scope.GetInstance(name); + } - return (Func) Func; - }; - } + return (Func)Func; + }; + } - public override object Resolve(Scope scope) + public override object Resolve(Scope scope) + { + T Func(string name) { - T Func(string name) => scope.GetInstance(name); - - return (Func) Func; + return scope.GetInstance(name); } + + return (Func)Func; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/FuncInstance.cs b/src/Lamar/IoC/Lazy/FuncInstance.cs index b0ca8586..f4e6815e 100644 --- a/src/Lamar/IoC/Lazy/FuncInstance.cs +++ b/src/Lamar/IoC/Lazy/FuncInstance.cs @@ -1,49 +1,48 @@ using System; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Instances; -using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Lazy +namespace Lamar.IoC.Lazy; + +internal class FuncInstance : Instance { - internal class FuncInstance : Instance + public FuncInstance() : base(typeof(Func), typeof(Func), ServiceLifetime.Transient) { + Name = "func_of_" + typeof(T).FullNameInCode().Sanitize(); + } - public FuncInstance() : base(typeof(Func), typeof(Func), ServiceLifetime.Transient) - { - Name = "func_of_" + typeof(T).FullNameInCode().Sanitize(); - } - - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new GetFuncFrame(this, typeof(T)).Variable; - } - - public override string WhyRequireServiceProvider(IMethodVariables method) - { - return "Func uses Lamar scopes directly"; - } - - public override bool RequiresServiceProvider(IMethodVariables method) => true; + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new GetFuncFrame(this, typeof(T)).Variable; + } - public override Func ToResolver(Scope topScope) - { - return scope => - { - Func func = scope.GetInstance; + public override string WhyRequireServiceProvider(IMethodVariables method) + { + return "Func uses Lamar scopes directly"; + } - return func; - }; - } + public override bool RequiresServiceProvider(IMethodVariables method) + { + return true; + } - public override object Resolve(Scope scope) + public override Func ToResolver(Scope topScope) + { + return scope => { Func func = scope.GetInstance; return func; - } + }; + } + + public override object Resolve(Scope scope) + { + Func func = scope.GetInstance; + return func; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/FuncOrLazyPolicy.cs b/src/Lamar/IoC/Lazy/FuncOrLazyPolicy.cs index 64ae2c85..e153eb13 100644 --- a/src/Lamar/IoC/Lazy/FuncOrLazyPolicy.cs +++ b/src/Lamar/IoC/Lazy/FuncOrLazyPolicy.cs @@ -2,30 +2,31 @@ using System.Linq; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Lazy +namespace Lamar.IoC.Lazy; + +internal class FuncOrLazyPolicy : IFamilyPolicy { - internal class FuncOrLazyPolicy : IFamilyPolicy + public ServiceFamily Build(Type type, ServiceGraph serviceGraph) { - public ServiceFamily Build(Type type, ServiceGraph serviceGraph) + if (type.Closes(typeof(Func<>))) { - if (type.Closes(typeof(Func<>))) - { - return new ServiceFamily(type, new IDecoratorPolicy[0], typeof(FuncInstance<>).CloseAndBuildAs(type.GetGenericArguments().Single())); - } - - if (type.Closes(typeof(Lazy<>))) - { - return new ServiceFamily(type, new IDecoratorPolicy[0], typeof(LazyInstance<>).CloseAndBuildAs(type.GetGenericArguments().Single())); - } - - if (type.Closes(typeof(Func<,>)) && type.GenericTypeArguments.First() == typeof(string)) - { - return new ServiceFamily(type, new IDecoratorPolicy[0], typeof(FuncByNameInstance<>).CloseAndBuildAs(type.GetGenericArguments().Last())); - } + return new ServiceFamily(type, new IDecoratorPolicy[0], + typeof(FuncInstance<>).CloseAndBuildAs(type.GetGenericArguments().Single())); + } - return null; + if (type.Closes(typeof(Lazy<>))) + { + return new ServiceFamily(type, new IDecoratorPolicy[0], + typeof(LazyInstance<>).CloseAndBuildAs(type.GetGenericArguments().Single())); } + + if (type.Closes(typeof(Func<,>)) && type.GenericTypeArguments.First() == typeof(string)) + { + return new ServiceFamily(type, new IDecoratorPolicy[0], + typeof(FuncByNameInstance<>).CloseAndBuildAs(type.GetGenericArguments().Last())); + } + + return null; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/GetFuncByNameFrame.cs b/src/Lamar/IoC/Lazy/GetFuncByNameFrame.cs index dd3bd908..ef227641 100644 --- a/src/Lamar/IoC/Lazy/GetFuncByNameFrame.cs +++ b/src/Lamar/IoC/Lazy/GetFuncByNameFrame.cs @@ -1,53 +1,52 @@ using System; using System.Linq.Expressions; using System.Reflection; -using Lamar.IoC.Frames; -using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; +using Lamar.IoC.Instances; + +namespace Lamar.IoC.Lazy; -namespace Lamar.IoC.Lazy +internal class GetFuncByNameFrame : TemplateFrame, IResolverFrame { - internal class GetFuncByNameFrame : TemplateFrame, IResolverFrame + private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.FactoryByNameFor)); + private readonly Type _serviceType; + + private object _scope; + + public GetFuncByNameFrame(Instance instance, Type innerType) { - private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.FactoryByNameFor)); - - private object _scope; - private readonly Type _serviceType; + _serviceType = innerType; + Variable = new ServiceVariable(instance, this); + } - public GetFuncByNameFrame(Instance instance, Type innerType) - { - _serviceType = innerType; - Variable = new ServiceVariable(instance, this); - } - - public Variable Variable { get; } + public Variable Variable { get; } - protected override string Template() - { - _scope = Arg(); - return $"System.Func {Variable.Usage} = name => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>(name);"; - } + public void WriteExpressions(LambdaDefinition definition) + { + var scope = definition.Scope(); + var closedMethod = _openMethod.MakeGenericMethod(_serviceType); + var expr = definition.ExpressionFor(Variable); + + var call = Expression.Call(scope, closedMethod); + var assign = Expression.Assign(expr, call); + + definition.Body.Add(assign); - public void WriteExpressions(LambdaDefinition definition) + + if (Next == null) { - var scope = definition.Scope(); - var closedMethod = _openMethod.MakeGenericMethod(_serviceType); - var expr = definition.ExpressionFor(Variable); - - var call = Expression.Call(scope, closedMethod); - var assign = Expression.Assign(expr, call); - - definition.Body.Add(assign); - - - if (Next == null) - { - definition.Body.Add(expr); - } + definition.Body.Add(expr); } } + + protected override string Template() + { + _scope = Arg(); + return + $"System.Func {Variable.Usage} = name => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>(name);"; + } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/GetFuncFrame.cs b/src/Lamar/IoC/Lazy/GetFuncFrame.cs index 712bdba1..7e3083e3 100644 --- a/src/Lamar/IoC/Lazy/GetFuncFrame.cs +++ b/src/Lamar/IoC/Lazy/GetFuncFrame.cs @@ -1,54 +1,52 @@ using System; -using System.Linq; using System.Linq.Expressions; using System.Reflection; -using Lamar.IoC.Frames; -using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; +using Lamar.IoC.Instances; + +namespace Lamar.IoC.Lazy; -namespace Lamar.IoC.Lazy +internal class GetFuncFrame : TemplateFrame, IResolverFrame { - internal class GetFuncFrame : TemplateFrame, IResolverFrame + private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.FactoryFor)); + private readonly Type _serviceType; + + private object _scope; + + public GetFuncFrame(Instance instance, Type innerType) { - private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.FactoryFor)); + _serviceType = innerType; + Variable = new ServiceVariable(instance, this); + } - private object _scope; - private readonly Type _serviceType; + public Variable Variable { get; } - public GetFuncFrame(Instance instance, Type innerType) - { - _serviceType = innerType; - Variable = new ServiceVariable(instance, this); - } - - public Variable Variable { get; } + public void WriteExpressions(LambdaDefinition definition) + { + var scope = definition.Scope(); + var closedMethod = _openMethod.MakeGenericMethod(_serviceType); + var expr = definition.ExpressionFor(Variable); - protected override string Template() - { - _scope = Arg(); - return $"System.Func<{_serviceType.FullNameInCode()}> {Variable.Usage} = () => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>();"; - } - - public void WriteExpressions(LambdaDefinition definition) + var call = Expression.Call(scope, closedMethod); + var assign = Expression.Assign(expr, call); + + definition.Body.Add(assign); + + + if (Next == null) { - var scope = definition.Scope(); - var closedMethod = _openMethod.MakeGenericMethod(_serviceType); - var expr = definition.ExpressionFor(Variable); - - var call = Expression.Call(scope, closedMethod); - var assign = Expression.Assign(expr, call); - - definition.Body.Add(assign); - - - if (Next == null) - { - definition.Body.Add(expr); - } + definition.Body.Add(expr); } } + + protected override string Template() + { + _scope = Arg(); + return + $"System.Func<{_serviceType.FullNameInCode()}> {Variable.Usage} = () => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>();"; + } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/GetLazyFrame.cs b/src/Lamar/IoC/Lazy/GetLazyFrame.cs index df62f9e6..b76909ae 100644 --- a/src/Lamar/IoC/Lazy/GetLazyFrame.cs +++ b/src/Lamar/IoC/Lazy/GetLazyFrame.cs @@ -1,54 +1,52 @@ using System; using System.Linq.Expressions; using System.Reflection; -using Lamar.IoC.Frames; -using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; +using Lamar.IoC.Instances; + +namespace Lamar.IoC.Lazy; -namespace Lamar.IoC.Lazy +internal class GetLazyFrame : TemplateFrame, IResolverFrame { - internal class GetLazyFrame : TemplateFrame, IResolverFrame + private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.LazyFor)); + private readonly Type _serviceType; + + private object _scope; + + public GetLazyFrame(Instance instance, Type innerType) { - - private static readonly MethodInfo _openMethod = typeof(Scope).GetMethod(nameof(Scope.LazyFor)); + _serviceType = innerType; + Variable = new ServiceVariable(instance, this); + } - private object _scope; - private readonly Type _serviceType; + public Variable Variable { get; } - public GetLazyFrame(Instance instance, Type innerType) - { - _serviceType = innerType; - Variable = new ServiceVariable(instance, this); - } - - public Variable Variable { get; } + public void WriteExpressions(LambdaDefinition definition) + { + var scope = definition.Scope(); + var closedMethod = _openMethod.MakeGenericMethod(_serviceType); + var expr = definition.ExpressionFor(Variable); - protected override string Template() - { - _scope = Arg(); - return $"var {Variable.Usage} = new System.Lazy<{_serviceType.FullNameInCode()}>(() => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>());"; - } - - public void WriteExpressions(LambdaDefinition definition) + var call = Expression.Call(scope, closedMethod); + var assign = Expression.Assign(expr, call); + + definition.Body.Add(assign); + + + if (Next == null) { - var scope = definition.Scope(); - var closedMethod = _openMethod.MakeGenericMethod(_serviceType); - var expr = definition.ExpressionFor(Variable); - - var call = Expression.Call(scope, closedMethod); - var assign = Expression.Assign(expr, call); - - definition.Body.Add(assign); - - - if (Next == null) - { - definition.Body.Add(expr); - } + definition.Body.Add(expr); } } + + protected override string Template() + { + _scope = Arg(); + return + $"var {Variable.Usage} = new System.Lazy<{_serviceType.FullNameInCode()}>(() => {_scope}.{nameof(IContainer.GetInstance)}<{_serviceType.FullNameInCode()}>());"; + } } \ No newline at end of file diff --git a/src/Lamar/IoC/Lazy/LazyInstance.cs b/src/Lamar/IoC/Lazy/LazyInstance.cs index d5400c70..7261bbf3 100644 --- a/src/Lamar/IoC/Lazy/LazyInstance.cs +++ b/src/Lamar/IoC/Lazy/LazyInstance.cs @@ -1,42 +1,43 @@ using System; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; using Lamar.IoC.Frames; using Lamar.IoC.Instances; using Lamar.IoC.Resolvers; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Lazy +namespace Lamar.IoC.Lazy; + +internal class LazyInstance : Instance, IResolver { - internal class LazyInstance : Instance, IResolver + public LazyInstance() : base(typeof(Lazy), typeof(Lazy), ServiceLifetime.Transient) { + Name = "lazy_of_" + typeof(T).NameInCode(); + } - public LazyInstance() : base(typeof(Lazy), typeof(Lazy), ServiceLifetime.Transient) - { - Name = "lazy_of_" + typeof(T).NameInCode(); - } - - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new GetLazyFrame(this, typeof(T)).Variable; - } - - - public override bool RequiresServiceProvider(IMethodVariables method) => true; - public override string WhyRequireServiceProvider(IMethodVariables method) - { - return "Lazy uses Lamar scopes directly"; - } - - public override object Resolve(Scope scope) - { - return new Lazy(scope.GetInstance); - } - - public override Func ToResolver(Scope topScope) - { - return s => new Lazy(s.GetInstance); - } + public override object Resolve(Scope scope) + { + return new Lazy(scope.GetInstance); + } + + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new GetLazyFrame(this, typeof(T)).Variable; + } + + public override bool RequiresServiceProvider(IMethodVariables method) + { + return true; + } + + public override string WhyRequireServiceProvider(IMethodVariables method) + { + return "Lazy uses Lamar scopes directly"; + } + + public override Func ToResolver(Scope topScope) + { + return s => new Lazy(s.GetInstance); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Policies/CloseGenericFamilyPolicy.cs b/src/Lamar/IoC/Policies/CloseGenericFamilyPolicy.cs index 674fb677..50a8b7ff 100644 --- a/src/Lamar/IoC/Policies/CloseGenericFamilyPolicy.cs +++ b/src/Lamar/IoC/Policies/CloseGenericFamilyPolicy.cs @@ -4,55 +4,55 @@ using Lamar.IoC.Instances; using Lamar.Scanning.Conventions; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +internal class CloseGenericFamilyPolicy : IFamilyPolicy { - internal class CloseGenericFamilyPolicy : IFamilyPolicy + public ServiceFamily Build(Type type, ServiceGraph graph) { - public ServiceFamily Build(Type type, ServiceGraph graph) + if (!type.IsGenericType) + { + return null; + } + + var basicType = type.GetGenericTypeDefinition(); + + if (graph.HasFamily(basicType)) { - if (!type.IsGenericType) return null; - - var basicType = type.GetGenericTypeDefinition(); - - if (graph.HasFamily(basicType)) - { - var basicFamily = graph.ResolveFamily(basicType); - var templatedParameterTypes = type.GetGenericArguments(); - - return basicFamily.CreateTemplatedClone(type, graph.DecoratorPolicies, templatedParameterTypes.ToArray()); - } - - try - { - return tryToConnect(type, graph); - } - catch (Exception) - { - return tryToConnect(type, graph); - } + var basicFamily = graph.ResolveFamily(basicType); + var templatedParameterTypes = type.GetGenericArguments(); + return basicFamily.CreateTemplatedClone(type, graph.DecoratorPolicies, templatedParameterTypes.ToArray()); } - - - private ServiceFamily tryToConnect(Type type, ServiceGraph graph) + try { - // RIGHT HERE: do the connections thing HERE! - var connectingTypes = graph.Services.ConnectedConcretions().Where(x => x.CanBeCastTo(type)).ToArray(); - - - if (connectingTypes.Any()) - { - var instances = connectingTypes.Select(x => new ConstructorInstance(type, x, ServiceLifetime.Transient)).ToArray(); - - return new ServiceFamily(type, new IDecoratorPolicy[0], instances); - } - - // This is a problem right here. Need this to be exposed - return graph.Families.Values.ToArray() - .FirstOrDefault(x => type.IsAssignableFrom(x.ServiceType)); + return tryToConnect(type, graph); } + catch (Exception) + { + return tryToConnect(type, graph); + } + } + + + private ServiceFamily tryToConnect(Type type, ServiceGraph graph) + { + // RIGHT HERE: do the connections thing HERE! + var connectingTypes = graph.Services.ConnectedConcretions().Where(x => x.CanBeCastTo(type)).ToArray(); + + + if (connectingTypes.Any()) + { + var instances = connectingTypes.Select(x => new ConstructorInstance(type, x, ServiceLifetime.Transient)) + .ToArray(); + + return new ServiceFamily(type, new IDecoratorPolicy[0], instances); + } + + // This is a problem right here. Need this to be exposed + return graph.Families.Values.ToArray() + .FirstOrDefault(x => type.IsAssignableFrom(x.ServiceType)); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Policies/ConcreteFamilyPolicy.cs b/src/Lamar/IoC/Policies/ConcreteFamilyPolicy.cs index 8100f8b8..494adab8 100644 --- a/src/Lamar/IoC/Policies/ConcreteFamilyPolicy.cs +++ b/src/Lamar/IoC/Policies/ConcreteFamilyPolicy.cs @@ -3,44 +3,53 @@ using JasperFx.Core.Reflection; using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +internal class ConcreteFamilyPolicy : IFamilyPolicy { - internal class ConcreteFamilyPolicy : IFamilyPolicy + public ServiceFamily Build(Type type, ServiceGraph serviceGraph) { - public static bool IsReallyPublic(Type type) + if (type.IsGenericTypeDefinition) { - if (type.IsPublic) return true; + return null; + } + + if (!type.IsConcrete()) + { + return null; + } - if (type.MemberType == MemberTypes.NestedType) - { - return IsReallyPublic(type.ReflectedType); - } - return false; + if (!IsReallyPublic(type)) + { + return null; } - - public ServiceFamily Build(Type type, ServiceGraph serviceGraph) + + if (serviceGraph.CouldBuild(type, out var message)) { - if (type.IsGenericTypeDefinition) return null; - if (!type.IsConcrete()) return null; - - - if (!IsReallyPublic(type)) return null; - - if (serviceGraph.CouldBuild(type, out var message)) - { - return new ServiceFamily(type, serviceGraph.DecoratorPolicies, new ConstructorInstance(type, type, ServiceLifetime.Transient)); - } - else - { - var empty = new ServiceFamily(type, new IDecoratorPolicy[0], new Instance[0]); - empty.CannotBeResolvedMessage = message; - - return empty; - } + return new ServiceFamily(type, serviceGraph.DecoratorPolicies, + new ConstructorInstance(type, type, ServiceLifetime.Transient)); + } + + var empty = new ServiceFamily(type, new IDecoratorPolicy[0]); + empty.CannotBeResolvedMessage = message; + return empty; + } + + public static bool IsReallyPublic(Type type) + { + if (type.IsPublic) + { + return true; } + + if (type.MemberType == MemberTypes.NestedType) + { + return IsReallyPublic(type.ReflectedType); + } + + return false; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Policies/EmptyFamilyPolicy.cs b/src/Lamar/IoC/Policies/EmptyFamilyPolicy.cs index 67e912d9..50028291 100644 --- a/src/Lamar/IoC/Policies/EmptyFamilyPolicy.cs +++ b/src/Lamar/IoC/Policies/EmptyFamilyPolicy.cs @@ -1,15 +1,16 @@ using System; -using Lamar.IoC.Instances; -namespace Lamar +namespace Lamar; + +internal class EmptyFamilyPolicy : IFamilyPolicy { - internal class EmptyFamilyPolicy : IFamilyPolicy + public ServiceFamily Build(Type type, ServiceGraph serviceGraph) { - public ServiceFamily Build(Type type, ServiceGraph serviceGraph) + if (!type.IsGenericTypeDefinition) { - if (!type.IsGenericTypeDefinition) return new ServiceFamily(type, new IDecoratorPolicy[0], new Instance[0]); - - return null; + return new ServiceFamily(type, new IDecoratorPolicy[0]); } + + return null; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Policies/LamarOverrides.cs b/src/Lamar/IoC/Policies/LamarOverrides.cs index 3f559eac..2393e088 100644 --- a/src/Lamar/IoC/Policies/LamarOverrides.cs +++ b/src/Lamar/IoC/Policies/LamarOverrides.cs @@ -1,16 +1,15 @@ -namespace Lamar +namespace Lamar; + +/// +/// Used to apply "this must win" service overrides regardless of the order of +/// registration +/// +internal class LamarOverrides : IRegistrationPolicy { - /// - /// Used to apply "this must win" service overrides regardless of the order of - /// registration - /// - internal class LamarOverrides : IRegistrationPolicy - { - public void Apply(ServiceRegistry services) - { - services.AddRange(Overrides); - } + public ServiceRegistry Overrides { get; } = new(); - public ServiceRegistry Overrides { get; } = new ServiceRegistry(); + public void Apply(ServiceRegistry services) + { + services.AddRange(Overrides); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/CastScopeFrame.cs b/src/Lamar/IoC/Resolvers/CastScopeFrame.cs index b138a559..b2dc0d76 100644 --- a/src/Lamar/IoC/Resolvers/CastScopeFrame.cs +++ b/src/Lamar/IoC/Resolvers/CastScopeFrame.cs @@ -5,37 +5,37 @@ using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +internal class CastScopeFrame : SyncFrame, IResolverFrame { - internal class CastScopeFrame : SyncFrame, IResolverFrame + private Variable _scope; + + public CastScopeFrame(Type interfaceType) { - private Variable _scope; + Variable = new Variable(interfaceType, this); + } - public CastScopeFrame(Type interfaceType) - { - Variable = new Variable(interfaceType, this); - } - - public Variable Variable { get; } + public Variable Variable { get; } - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}) {_scope.Usage};"); - Next?.GenerateCode(method, writer); - } + public void WriteExpressions(LambdaDefinition definition) + { + var variableExpr = definition.RegisterExpression(Variable); + definition.Body.Add(Expression.Assign(variableExpr, + Expression.Convert(definition.ExpressionFor(_scope), Variable.VariableType))); + } - public override IEnumerable FindVariables(IMethodVariables chain) - { - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; - } + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write($"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}) {_scope.Usage};"); + Next?.GenerateCode(method, writer); + } - public void WriteExpressions(LambdaDefinition definition) - { - var variableExpr = definition.RegisterExpression(Variable); - definition.Body.Add(Expression.Assign(variableExpr, Expression.Convert(definition.ExpressionFor(_scope), Variable.VariableType))); - } + public override IEnumerable FindVariables(IMethodVariables chain) + { + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/IResolver.cs b/src/Lamar/IoC/Resolvers/IResolver.cs index 529aa055..71cb623a 100644 --- a/src/Lamar/IoC/Resolvers/IResolver.cs +++ b/src/Lamar/IoC/Resolvers/IResolver.cs @@ -1,14 +1,12 @@ using System; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public interface IResolver { - public interface IResolver - { - object Resolve(Scope scope); - Type ServiceType { get; } - - string Name { get; set; } - int Hash { get; set; } - - } + Type ServiceType { get; } + + string Name { get; set; } + int Hash { get; set; } + object Resolve(Scope scope); } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/ScopeInstance.cs b/src/Lamar/IoC/Resolvers/ScopeInstance.cs index ddb96587..f50942ec 100644 --- a/src/Lamar/IoC/Resolvers/ScopeInstance.cs +++ b/src/Lamar/IoC/Resolvers/ScopeInstance.cs @@ -1,101 +1,101 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using Lamar.IoC.Frames; -using Lamar.IoC.Instances; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Expressions; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.Reflection; +using Lamar.IoC.Frames; +using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public class RootScopeInstance : Instance, IResolver { + public RootScopeInstance() : base(typeof(T), typeof(T), ServiceLifetime.Singleton) + { + Name = typeof(T).Name; + } + + public override object Resolve(Scope scope) + { + return scope.Root; + } + + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new CastRootScopeFrame(typeof(T)).Variable; + } - public class RootScopeInstance : Instance, IResolver + public override Func ToResolver(Scope topScope) { - public RootScopeInstance() : base(typeof(T), typeof(T), ServiceLifetime.Singleton) - { - Name = typeof(T).Name; - } - - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new CastRootScopeFrame(typeof(T)).Variable; - } - - public override Func ToResolver(Scope topScope) - { - return s => topScope; - } - - public override object Resolve(Scope scope) - { - return scope.Root; - } - - public override string ToString() - { - return $"Current {typeof(T).NameInCode()}"; - } + return s => topScope; } - - public class CastRootScopeFrame : SyncFrame, IResolverFrame + + public override string ToString() { - private Variable _scope; - - public CastRootScopeFrame(Type interfaceType) - { - Variable = new Variable(interfaceType, this); - } - - public Variable Variable { get; } - - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.Write($"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}) {_scope.Usage}.{nameof(Scope.Root)};"); - Next?.GenerateCode(method, writer); - } - - public override IEnumerable FindVariables(IMethodVariables chain) - { - _scope = chain.FindVariable(typeof(Scope)); - yield return _scope; - } - - public void WriteExpressions(LambdaDefinition definition) - { - var variableExpr = definition.RegisterExpression(Variable); - definition.Body.Add(Expression.Assign(variableExpr, Expression.Convert(definition.ExpressionFor(_scope), Variable.VariableType))); - } + return $"Current {typeof(T).NameInCode()}"; } - - public class ScopeInstance : Instance, IResolver +} + +public class CastRootScopeFrame : SyncFrame, IResolverFrame +{ + private Variable _scope; + + public CastRootScopeFrame(Type interfaceType) + { + Variable = new Variable(interfaceType, this); + } + + public Variable Variable { get; } + + public void WriteExpressions(LambdaDefinition definition) + { + var variableExpr = definition.RegisterExpression(Variable); + definition.Body.Add(Expression.Assign(variableExpr, + Expression.Convert(definition.ExpressionFor(_scope), Variable.VariableType))); + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write( + $"var {Variable.Usage} = ({Variable.VariableType.FullNameInCode()}) {_scope.Usage}.{nameof(Scope.Root)};"); + Next?.GenerateCode(method, writer); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + _scope = chain.FindVariable(typeof(Scope)); + yield return _scope; + } +} + +public class ScopeInstance : Instance, IResolver +{ + public ScopeInstance() : base(typeof(T), typeof(T), ServiceLifetime.Scoped) + { + Name = typeof(T).Name; + } + + public override object Resolve(Scope scope) + { + return scope; + } + + public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) + { + return new CastScopeFrame(typeof(T)).Variable; + } + + public override Func ToResolver(Scope topScope) + { + return s => s; + } + + public override string ToString() { - public ScopeInstance() : base(typeof(T), typeof(T), ServiceLifetime.Scoped) - { - Name = typeof(T).Name; - } - - public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) - { - return new CastScopeFrame(typeof(T)).Variable; - } - - public override Func ToResolver(Scope topScope) - { - return s => s; - } - - public override object Resolve(Scope scope) - { - return scope; - } - - public override string ToString() - { - return $"Current {typeof(T).NameInCode()}"; - } + return $"Current {typeof(T).NameInCode()}"; } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/ScopeResolver.cs b/src/Lamar/IoC/Resolvers/ScopeResolver.cs index aa5ffc56..779a0f07 100644 --- a/src/Lamar/IoC/Resolvers/ScopeResolver.cs +++ b/src/Lamar/IoC/Resolvers/ScopeResolver.cs @@ -1,17 +1,16 @@ using System; using Lamar.IoC.Instances; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public class ScopeResolver : IResolver { - public class ScopeResolver : IResolver + public object Resolve(Scope scope) { - public object Resolve(Scope scope) - { - return scope; - } - - public Type ServiceType { get; } = typeof(Scope); - public string Name { get; set; } = "default"; - public int Hash { get; set; } = Instance.HashCode(typeof(Scope), "default"); + return scope; } + + public Type ServiceType { get; } = typeof(Scope); + public string Name { get; set; } = "default"; + public int Hash { get; set; } = Instance.HashCode(typeof(Scope), "default"); } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/ScopedLambdaResolver.cs b/src/Lamar/IoC/Resolvers/ScopedLambdaResolver.cs index 214b2488..212c79bf 100644 --- a/src/Lamar/IoC/Resolvers/ScopedLambdaResolver.cs +++ b/src/Lamar/IoC/Resolvers/ScopedLambdaResolver.cs @@ -1,22 +1,19 @@ using System; using JasperFx.Core.Reflection; -using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public class ScopedLambdaResolver : ScopedResolver { - public class ScopedLambdaResolver : ScopedResolver - { - private readonly Func _builder; + private readonly Func _builder; - public ScopedLambdaResolver(Func builder) - { - _builder = builder; - } + public ScopedLambdaResolver(Func builder) + { + _builder = builder; + } - public override T Build(Scope scope) - { - return _builder(scope.As()); - } + public override T Build(Scope scope) + { + return _builder(scope.As()); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/ScopedResolver.cs b/src/Lamar/IoC/Resolvers/ScopedResolver.cs index eb88afcb..40f4bb5a 100644 --- a/src/Lamar/IoC/Resolvers/ScopedResolver.cs +++ b/src/Lamar/IoC/Resolvers/ScopedResolver.cs @@ -1,43 +1,38 @@ using System; using JasperFx.Core; -using Lamar.Util; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public abstract class ScopedResolver : IResolver { - public abstract class ScopedResolver : IResolver + private readonly object _locker = new(); + public Type ServiceType => typeof(T); + + public object Resolve(Scope scope) { - public Type ServiceType => typeof(T); - - private readonly object _locker = new object(); + if (scope.Services.TryFind(Hash, out var service)) + { + return service; + } - public object Resolve(Scope scope) + lock (_locker) { - if (scope.Services.TryFind(Hash, out object service)) + if (scope.Services.TryFind(Hash, out service)) { return service; } - lock (_locker) - { - if (scope.Services.TryFind(Hash, out service)) - { - return service; - } - - service = (T) Build(scope); - scope.Services = scope.Services.AddOrUpdate(Hash, service); - - scope.TryAddDisposable(service); + service = Build(scope); + scope.Services = scope.Services.AddOrUpdate(Hash, service); - return service; - } - + scope.TryAddDisposable(service); + return service; } + } - public abstract T Build(Scope scope); + public string Name { get; set; } + public int Hash { get; set; } - public string Name { get; set; } - public int Hash { get; set; } - } + public abstract T Build(Scope scope); } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/SingletonLambdaResolver.cs b/src/Lamar/IoC/Resolvers/SingletonLambdaResolver.cs index 6470148d..19c0b745 100644 --- a/src/Lamar/IoC/Resolvers/SingletonLambdaResolver.cs +++ b/src/Lamar/IoC/Resolvers/SingletonLambdaResolver.cs @@ -1,22 +1,19 @@ using System; using JasperFx.Core.Reflection; -using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public class SingletonLambdaResolver : SingletonResolver { - public class SingletonLambdaResolver : SingletonResolver + private readonly Func _builder; + + public SingletonLambdaResolver(Func builder, Scope topLevelScope) : base(topLevelScope) + { + _builder = builder; + } + + public override T Build(Scope scope) { - private readonly Func _builder; - - public SingletonLambdaResolver(Func builder, Scope topLevelScope) : base(topLevelScope) - { - _builder = builder; - } - - public override T Build(Scope scope) - { - return _builder(scope.As()); - } + return _builder(scope.As()); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/SingletonResolver.cs b/src/Lamar/IoC/Resolvers/SingletonResolver.cs index 12cc8dbd..dc30335d 100644 --- a/src/Lamar/IoC/Resolvers/SingletonResolver.cs +++ b/src/Lamar/IoC/Resolvers/SingletonResolver.cs @@ -1,61 +1,59 @@ using System; using JasperFx.Core; -using Lamar.Util; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public abstract class SingletonResolver : IResolver { - public abstract class SingletonResolver : IResolver + private readonly object _locker = new(); + private readonly Scope _topLevelScope; + + private T _service; + + public SingletonResolver(Scope topLevelScope) { - private readonly Scope _topLevelScope; - private readonly object _locker = new object(); - - public Type ServiceType => typeof(T); - - private T _service; - - public SingletonResolver(Scope topLevelScope) - { - _topLevelScope = topLevelScope; - } + _topLevelScope = topLevelScope; + } - public object Resolve(Scope scope) + public Type ServiceType => typeof(T); + + public object Resolve(Scope scope) + { + if (_service != null) { - if (_service != null) return _service; + return _service; + } - if (_topLevelScope.Services.TryFind(Hash, out var service)) - { - _service = (T) service; - return _service; - } + if (_topLevelScope.Services.TryFind(Hash, out var service)) + { + _service = (T)service; + return _service; + } - lock (_locker) + lock (_locker) + { + if (_service == null) { - if (_service == null) + if (_topLevelScope.Services.TryFind(Hash, out var o)) { - if (_topLevelScope.Services.TryFind(Hash, out var o)) - { - _service = (T) o; - } - else - { - _service = Build(_topLevelScope); - _topLevelScope.TryAddDisposable(_service); - - _topLevelScope.Services = _topLevelScope.Services.AddOrUpdate(Hash, _service); - } + _service = (T)o; } - } + else + { + _service = Build(_topLevelScope); + _topLevelScope.TryAddDisposable(_service); - return _service; + _topLevelScope.Services = _topLevelScope.Services.AddOrUpdate(Hash, _service); + } + } } - - public abstract T Build(Scope scope); - - public string Name { get; set; } - public int Hash { get; set; } + return _service; } + public string Name { get; set; } + public int Hash { get; set; } + public abstract T Build(Scope scope); } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/TransientLambdaResolver.cs b/src/Lamar/IoC/Resolvers/TransientLambdaResolver.cs index dacfa1bc..e2ff34a3 100644 --- a/src/Lamar/IoC/Resolvers/TransientLambdaResolver.cs +++ b/src/Lamar/IoC/Resolvers/TransientLambdaResolver.cs @@ -1,22 +1,19 @@ using System; using JasperFx.Core.Reflection; -using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public class TransientLambdaResolver : TransientResolver { - public class TransientLambdaResolver : TransientResolver + private readonly Func _builder; + + public TransientLambdaResolver(Func builder) + { + _builder = builder; + } + + public override T Build(Scope scope) { - private readonly Func _builder; - - public TransientLambdaResolver(Func builder) - { - _builder = builder; - } - - public override T Build(Scope scope) - { - return _builder(scope.As()); - } + return _builder(scope.As()); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Resolvers/TransientResolver.cs b/src/Lamar/IoC/Resolvers/TransientResolver.cs index 0526ba32..b241f081 100644 --- a/src/Lamar/IoC/Resolvers/TransientResolver.cs +++ b/src/Lamar/IoC/Resolvers/TransientResolver.cs @@ -1,22 +1,21 @@ using System; -namespace Lamar.IoC.Resolvers +namespace Lamar.IoC.Resolvers; + +public abstract class TransientResolver : IResolver { - public abstract class TransientResolver : IResolver + public object Resolve(Scope scope) { - public object Resolve(Scope scope) - { - var service = Build(scope); - scope.TryAddDisposable(service); - - return service; - } - - public abstract T Build(Scope scope); + var service = Build(scope); + scope.TryAddDisposable(service); - public Type ServiceType => typeof(T); - - public string Name { get; set; } - public int Hash { get; set; } + return service; } + + public Type ServiceType => typeof(T); + + public string Name { get; set; } + public int Hash { get; set; } + + public abstract T Build(Scope scope); } \ No newline at end of file diff --git a/src/Lamar/IoC/Scope.cs b/src/Lamar/IoC/Scope.cs index 45dee221..79129532 100644 --- a/src/Lamar/IoC/Scope.cs +++ b/src/Lamar/IoC/Scope.cs @@ -6,430 +6,471 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Model; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; using Lamar.Diagnostics; using Lamar.IoC.Diagnostics; using Lamar.IoC.Frames; using Lamar.IoC.Instances; -using Lamar.Util; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Model; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; +namespace Lamar.IoC; -namespace Lamar.IoC -{ - #region sample_Scope-Declarations - public class Scope : IServiceContext, IServiceProviderIsService +#region sample_Scope-Declarations - #endregion - { - protected bool _hasDisposed; +public class Scope : IServiceContext, IServiceProviderIsService - public static Scope Empty() - { - return new Scope(new ServiceRegistry()); - } - - public Scope(IServiceCollection services) - { - Root = this; + #endregion - ServiceGraph = new ServiceGraph(services, this); - - ServiceGraph.Initialize(); - } +{ + protected bool _hasDisposed; - protected Scope(){} + // don't build this if you don't need it + private Dictionary _injected; - public bool IsService(Type serviceType) - { - return ServiceGraph.CanBeServiceByNetCoreRules(serviceType); - } + internal ImHashMap Services = ImHashMap.Empty; - public Scope Root { get; protected set; } + public Scope(IServiceCollection services) + { + Root = this; - public Scope(ServiceGraph serviceGraph, Scope root) - { - ServiceGraph = serviceGraph; - Root = root ?? throw new ArgumentNullException(nameof(root)); - } + ServiceGraph = new ServiceGraph(services, this); - /// - /// Asserts that this container is not disposed yet. - /// - /// If the container is disposed. - protected void assertNotDisposed() - { - if (!_hasDisposed) return; + ServiceGraph.Initialize(); + } - throw new ObjectDisposedException("This Container has been disposed"); - } + protected Scope() + { + } + public Scope(ServiceGraph serviceGraph, Scope root) + { + ServiceGraph = serviceGraph; + Root = root ?? throw new ArgumentNullException(nameof(root)); + } - public DisposalLock DisposalLock { get; set; } = DisposalLock.Unlocked; + public Scope Root { get; protected set; } - public IModel Model => new QueryModel(this); + public DisposalLock DisposalLock { get; set; } = DisposalLock.Unlocked; - internal ServiceGraph ServiceGraph { get; set;} + internal ServiceGraph ServiceGraph { get; set; } - public ConcurrentBag Disposables { get; } = new ConcurrentBag(); - - internal IEnumerable AllDisposables => Disposables; + public ConcurrentBag Disposables { get; } = new(); - internal ImHashMap Services = ImHashMap.Empty; + internal IEnumerable AllDisposables => Disposables; - public virtual void Dispose() - { - if (DisposalLock == DisposalLock.ThrowOnDispose) throw new InvalidOperationException("This Container has DisposalLock = DisposalLock.ThrowOnDispose and cannot be disposed until the lock is cleared"); + public IServiceProvider ServiceProvider => this; - if (_hasDisposed) return; - _hasDisposed = true; - var distinctDisposables = Disposables.Distinct().ToArray(); - // clear disposables bag to prevent memory leak. current implementation of ConcurrentBag is using thread local storage and in some cases - // e.g. an object from Disposables collection is referencing this Scope instance the whole graph can stay in memory after it was disposed - while (Disposables.TryTake(out _)) { } + public IModel Model => new QueryModel(this); - if (DisposalLock == DisposalLock.Ignore) return; - - foreach (var disposable in distinctDisposables) - { - disposable.SafeDispose(); - } - } - - public virtual async ValueTask DisposeAsync() + public virtual void Dispose() + { + if (DisposalLock == DisposalLock.ThrowOnDispose) { - if (DisposalLock == DisposalLock.ThrowOnDispose) throw new InvalidOperationException("This Container has DisposalLock = DisposalLock.ThrowOnDispose and cannot be disposed until the lock is cleared"); - - if (_hasDisposed) return; - _hasDisposed = true; - - var distinctDisposables = Disposables.Distinct().ToArray(); - // clear disposables bag to prevent memory leak. current implementation of ConcurrentBag is using thread local storage and in some cases - // e.g. an object from Disposables collection is referencing this Scope instance the whole graph can stay in memory after it was disposed - while (Disposables.TryTake(out _)) { } - - if (DisposalLock == DisposalLock.Ignore) return; - - foreach (var disposable in distinctDisposables) - { - if (disposable is IAsyncDisposable asyncDisposable) - { - try - { - await asyncDisposable.DisposeAsync(); - } - catch (Exception) - { - // Yup, don't let that go out - } - } - else - { - disposable.SafeDispose(); - } - } + throw new InvalidOperationException( + "This Container has DisposalLock = DisposalLock.ThrowOnDispose and cannot be disposed until the lock is cleared"); } - public IServiceProvider ServiceProvider => this; - - public object GetService(Type serviceType) + if (_hasDisposed) { - return TryGetInstance(serviceType); + return; } - public T GetInstance() - { - return (T) GetInstance(typeof(T)); - } + _hasDisposed = true; - public T GetInstance(string name) + var distinctDisposables = Disposables.Distinct().ToArray(); + // clear disposables bag to prevent memory leak. current implementation of ConcurrentBag is using thread local storage and in some cases + // e.g. an object from Disposables collection is referencing this Scope instance the whole graph can stay in memory after it was disposed + while (Disposables.TryTake(out _)) { - return (T) GetInstance(typeof(T), name); } - public object GetInstance(Type serviceType) + if (DisposalLock == DisposalLock.Ignore) { - assertNotDisposed(); - var resolver = ServiceGraph.FindResolver(serviceType); - - if (resolver == null) - { - if (ServiceGraph.Families.TryGetValue(serviceType, out var family)) - { - if (family.CannotBeResolvedMessage.IsNotEmpty()) - { - throw new LamarMissingRegistrationException(family); - } - } - - throw new LamarMissingRegistrationException(serviceType); - } - - return resolver(this); + return; } - public object GetInstance(Type serviceType, string name) - { - assertNotDisposed(); - - var instance = ServiceGraph.FindInstance(serviceType, name); - if (instance == null) - { - throw new LamarMissingRegistrationException(serviceType, name); - } - - return instance.Resolve(this); - } + foreach (var disposable in distinctDisposables) disposable.SafeDispose(); + } - public T TryGetInstance() + public virtual async ValueTask DisposeAsync() + { + if (DisposalLock == DisposalLock.ThrowOnDispose) { - return (T)(TryGetInstance(typeof(T)) ?? default(T)); + throw new InvalidOperationException( + "This Container has DisposalLock = DisposalLock.ThrowOnDispose and cannot be disposed until the lock is cleared"); } - public T TryGetInstance(string name) + if (_hasDisposed) { - return (T)(TryGetInstance(typeof(T), name) ?? default(T)); + return; } - public object TryGetInstance(Type serviceType) - { - assertNotDisposed(); - return ServiceGraph.FindResolver(serviceType)?.Invoke(this); - } + _hasDisposed = true; - public object TryGetInstance(Type serviceType, string name) + var distinctDisposables = Disposables.Distinct().ToArray(); + // clear disposables bag to prevent memory leak. current implementation of ConcurrentBag is using thread local storage and in some cases + // e.g. an object from Disposables collection is referencing this Scope instance the whole graph can stay in memory after it was disposed + while (Disposables.TryTake(out _)) { - assertNotDisposed(); - var instance = ServiceGraph.FindInstance(serviceType, name); - return instance?.Resolve(this); } - public T QuickBuild() + if (DisposalLock == DisposalLock.Ignore) { - return (T) QuickBuild(typeof(T)); - + return; } - public object QuickBuild(Type objectType) + foreach (var disposable in distinctDisposables) { - assertNotDisposed(); - - if (!objectType.IsConcrete()) throw new InvalidOperationException("Type must be concrete"); - - var constructorInstance = new ConstructorInstance(objectType, objectType, ServiceLifetime.Transient); - var ctor = constructorInstance.DetermineConstructor(ServiceGraph, out var message); - var setters = constructorInstance.FindSetters(ServiceGraph); - - if (ctor == null) throw new InvalidOperationException(message); - - var dependencies = ctor.GetParameters().Select(x => + if (disposable is IAsyncDisposable asyncDisposable) { - var instance = ServiceGraph.FindInstance(x); - - if (instance == null) throw new InvalidOperationException($"Cannot QuickBuild type {objectType.GetFullName()} because Lamar cannot determine how to build required dependency {x.ParameterType.FullNameInCode()}"); - try { - return instance.QuickResolve(this); + await asyncDisposable.DisposeAsync(); } catch (Exception) { - // #sadtrombone, do it the heavy way instead - return instance.Resolve(this); + // Yup, don't let that go out } - }).ToArray(); - - var service = ctor.Invoke(dependencies); - foreach (var setter in setters) + } + else { - setter.ApplyQuickBuildProperties(service, this); + disposable.SafeDispose(); } - - return service; } + } - public IReadOnlyList QuickBuildAll() - { - assertNotDisposed(); - return ServiceGraph.FindAll(typeof(T)).Select(x => x.QuickResolve(this)).OfType().ToList(); - } + public object GetService(Type serviceType) + { + return TryGetInstance(serviceType); + } - public void BuildUp(object target) - { - var objectType = target.GetType(); - var constructorInstance = new ConstructorInstance(objectType, objectType, ServiceLifetime.Transient); - var setters = constructorInstance.FindSetters(ServiceGraph); + public T GetInstance() + { + return (T)GetInstance(typeof(T)); + } - foreach (var setter in setters) + public T GetInstance(string name) + { + return (T)GetInstance(typeof(T), name); + } + + public object GetInstance(Type serviceType) + { + assertNotDisposed(); + var resolver = ServiceGraph.FindResolver(serviceType); + + if (resolver == null) + { + if (ServiceGraph.Families.TryGetValue(serviceType, out var family)) { - setter.ApplyQuickBuildProperties(target, this); + if (family.CannotBeResolvedMessage.IsNotEmpty()) + { + throw new LamarMissingRegistrationException(family); + } } + + throw new LamarMissingRegistrationException(serviceType); } - public IReadOnlyList GetAllInstances() + return resolver(this); + } + + public object GetInstance(Type serviceType, string name) + { + assertNotDisposed(); + + var instance = ServiceGraph.FindInstance(serviceType, name); + if (instance == null) { - assertNotDisposed(); - return ServiceGraph.FindAll(typeof(T)).Select(x => x.Resolve(this)).OfType().ToList(); + throw new LamarMissingRegistrationException(serviceType, name); } - public IEnumerable GetAllInstances(Type serviceType) + return instance.Resolve(this); + } + + public T TryGetInstance() + { + return (T)(TryGetInstance(typeof(T)) ?? default(T)); + } + + public T TryGetInstance(string name) + { + return (T)(TryGetInstance(typeof(T), name) ?? default(T)); + } + + public object TryGetInstance(Type serviceType) + { + assertNotDisposed(); + return ServiceGraph.FindResolver(serviceType)?.Invoke(this); + } + + public object TryGetInstance(Type serviceType, string name) + { + assertNotDisposed(); + var instance = ServiceGraph.FindInstance(serviceType, name); + return instance?.Resolve(this); + } + + public T QuickBuild() + { + return (T)QuickBuild(typeof(T)); + } + + public object QuickBuild(Type objectType) + { + assertNotDisposed(); + + if (!objectType.IsConcrete()) { - assertNotDisposed(); - return ServiceGraph.FindAll(serviceType).Select(x => x.Resolve(this)).ToArray(); + throw new InvalidOperationException("Type must be concrete"); } + var constructorInstance = new ConstructorInstance(objectType, objectType, ServiceLifetime.Transient); + var ctor = constructorInstance.DetermineConstructor(ServiceGraph, out var message); + var setters = constructorInstance.FindSetters(ServiceGraph); - public string WhatDoIHave(Type serviceType = null, Assembly assembly = null, string @namespace = null, - string typeName = null) + if (ctor == null) { - assertNotDisposed(); - - var writer = new WhatDoIHaveWriter(Model); - return writer.GetText(new ModelQuery - { - Assembly = assembly, - Namespace = @namespace, - ServiceType = serviceType, - TypeName = typeName - }); + throw new InvalidOperationException(message); } - public string HowDoIBuild(Type serviceType = null, Assembly assembly = null, string @namespace = null, - string typeName = null) + var dependencies = ctor.GetParameters().Select(x => { - assertNotDisposed(); + var instance = ServiceGraph.FindInstance(x); - var writer = new WhatDoIHaveWriter(Model); - return writer.GetText(new ModelQuery + if (instance == null) { - Assembly = assembly, - Namespace = @namespace, - ServiceType = serviceType, - TypeName = typeName - }, display: WhatDoIHaveDisplay.BuildPlan); - } + throw new InvalidOperationException( + $"Cannot QuickBuild type {objectType.GetFullName()} because Lamar cannot determine how to build required dependency {x.ParameterType.FullNameInCode()}"); + } - /// - /// Returns a textual report of all the assembly scanners used to build up this Container - /// - /// - public string WhatDidIScan() - { - assertNotDisposed(); + try + { + return instance.QuickResolve(this); + } + catch (Exception) + { + // #sadtrombone, do it the heavy way instead + return instance.Resolve(this); + } + }).ToArray(); - var scanners = Model.Scanners; + var service = ctor.Invoke(dependencies); + foreach (var setter in setters) setter.ApplyQuickBuildProperties(service, this); - if (!scanners.Any()) return "No type scanning in this Container"; + return service; + } - using (var writer = new StringWriter()) - { - writer.WriteLine("All Scanners"); - writer.WriteLine("================================================================"); + public IReadOnlyList QuickBuildAll() + { + assertNotDisposed(); + return ServiceGraph.FindAll(typeof(T)).Select(x => x.QuickResolve(this)).OfType().ToList(); + } - scanners.Each(scanner => - { - scanner.Describe(writer); + public IReadOnlyList GetAllInstances() + { + assertNotDisposed(); + return ServiceGraph.FindAll(typeof(T)).Select(x => x.Resolve(this)).OfType().ToList(); + } - writer.WriteLine(); - writer.WriteLine(); - }); + public IEnumerable GetAllInstances(Type serviceType) + { + assertNotDisposed(); + return ServiceGraph.FindAll(serviceType).Select(x => x.Resolve(this)).ToArray(); + } - var failed = TypeRepository.FailedAssemblies(); - if (failed.Any()) - { - writer.WriteLine(); - writer.WriteLine("Assemblies that failed in the call to Assembly.GetExportedTypes()"); - failed.Each(assem => { writer.WriteLine("* " + assem.Record.Name); }); - } - else - { - writer.WriteLine("No problems were encountered in exporting types from Assemblies"); - } - return writer.ToString(); - } - } + public string WhatDoIHave(Type serviceType = null, Assembly assembly = null, string @namespace = null, + string typeName = null) + { + assertNotDisposed(); - public IServiceVariableSource CreateServiceVariableSource() + var writer = new WhatDoIHaveWriter(Model); + return writer.GetText(new ModelQuery { - return new ServiceVariableSource(ServiceGraph); - } + Assembly = assembly, + Namespace = @namespace, + ServiceType = serviceType, + TypeName = typeName + }); + } + + public string HowDoIBuild(Type serviceType = null, Assembly assembly = null, string @namespace = null, + string typeName = null) + { + assertNotDisposed(); - public string GenerateCodeWithInlineServices(GeneratedAssembly assembly) + var writer = new WhatDoIHaveWriter(Model); + return writer.GetText(new ModelQuery { - return assembly.GenerateCode(new ServiceVariableSource(ServiceGraph)); - } + Assembly = assembly, + Namespace = @namespace, + ServiceType = serviceType, + TypeName = typeName + }, display: WhatDoIHaveDisplay.BuildPlan); + } - // don't build this if you don't need it - private Dictionary _injected; + /// + /// Returns a textual report of all the assembly scanners used to build up this Container + /// + /// + public string WhatDidIScan() + { + assertNotDisposed(); + + var scanners = Model.Scanners; + + if (!scanners.Any()) + { + return "No type scanning in this Container"; + } - public virtual void Inject( Type serviceType, object @object, bool replace ) + using (var writer = new StringWriter()) { - if ( !serviceType.IsAssignableFrom( @object.GetType() ) ) - throw new InvalidOperationException( $"{serviceType} is not assignable from {@object.GetType()}" ); + writer.WriteLine("All Scanners"); + writer.WriteLine("================================================================"); - if ( _injected == null ) + scanners.Each(scanner => { - _injected = new Dictionary(); - } + scanner.Describe(writer); - if ( replace ) + writer.WriteLine(); + writer.WriteLine(); + }); + + var failed = TypeRepository.FailedAssemblies(); + if (failed.Any()) { - _injected[serviceType] = @object; + writer.WriteLine(); + writer.WriteLine("Assemblies that failed in the call to Assembly.GetExportedTypes()"); + failed.Each(assem => { writer.WriteLine("* " + assem.Record.Name); }); } - else { - _injected.Add( serviceType, @object ); + writer.WriteLine("No problems were encountered in exporting types from Assemblies"); } + + return writer.ToString(); } + } + + public IServiceVariableSource CreateServiceVariableSource() + { + return new ServiceVariableSource(ServiceGraph); + } + + public bool IsService(Type serviceType) + { + return ServiceGraph.CanBeServiceByNetCoreRules(serviceType); + } + + public static Scope Empty() + { + return new Scope(new ServiceRegistry()); + } + + /// + /// Asserts that this container is not disposed yet. + /// + /// If the container is disposed. + protected void assertNotDisposed() + { + if (!_hasDisposed) + { + return; + } + + throw new ObjectDisposedException("This Container has been disposed"); + } + + public void BuildUp(object target) + { + var objectType = target.GetType(); + var constructorInstance = new ConstructorInstance(objectType, objectType, ServiceLifetime.Transient); + var setters = constructorInstance.FindSetters(ServiceGraph); + + foreach (var setter in setters) setter.ApplyQuickBuildProperties(target, this); + } + + public string GenerateCodeWithInlineServices(GeneratedAssembly assembly) + { + return assembly.GenerateCode(new ServiceVariableSource(ServiceGraph)); + } - public void Inject( T @object ) => Inject( typeof(T), @object, false ); - public void Inject( T @object, bool replace = false ) => Inject( typeof(T), @object, replace ); - - public T GetInjected() + public virtual void Inject(Type serviceType, object @object, bool replace) + { + if (!serviceType.IsAssignableFrom(@object.GetType())) { - return (T) (_injected?.ContainsKey(typeof(T)) ?? false ? _injected[typeof(T)] : null); + throw new InvalidOperationException($"{serviceType} is not assignable from {@object.GetType()}"); } - /// - /// Some bookkeeping here. Tracks this to the scope's disposable tracking *if* it is disposable - /// - /// - public void TryAddDisposable(object @object) + if (_injected == null) { - switch (@object) - { - case IDisposable disposable: - Disposables.Add(disposable); - break; - case IAsyncDisposable a: - Disposables.Add(new AsyncDisposableWrapper(a)); - break; - } + _injected = new Dictionary(); } - public Func FactoryByNameFor() + if (replace) { - return GetInstance; + _injected[serviceType] = @object; } - public Func FactoryFor() + else { - return GetInstance; + _injected.Add(serviceType, @object); } + } - public Lazy LazyFor() + public void Inject(T @object) + { + Inject(typeof(T), @object, false); + } + + public void Inject(T @object, bool replace = false) + { + Inject(typeof(T), @object, replace); + } + + public T GetInjected() + { + return (T)(_injected?.ContainsKey(typeof(T)) ?? false ? _injected[typeof(T)] : null); + } + + /// + /// Some bookkeeping here. Tracks this to the scope's disposable tracking *if* it is disposable + /// + /// + public void TryAddDisposable(object @object) + { + switch (@object) { - return new Lazy(GetInstance); + case IDisposable disposable: + Disposables.Add(disposable); + break; + case IAsyncDisposable a: + Disposables.Add(new AsyncDisposableWrapper(a)); + break; } } -} + + public Func FactoryByNameFor() + { + return GetInstance; + } + + public Func FactoryFor() + { + return GetInstance; + } + + public Lazy LazyFor() + { + return new Lazy(GetInstance); + } +} \ No newline at end of file diff --git a/src/Lamar/IoC/Setters/ISetterPolicy.cs b/src/Lamar/IoC/Setters/ISetterPolicy.cs index ab1ff9d5..a65e0ebf 100644 --- a/src/Lamar/IoC/Setters/ISetterPolicy.cs +++ b/src/Lamar/IoC/Setters/ISetterPolicy.cs @@ -1,13 +1,12 @@ using System.Reflection; -namespace Lamar.IoC.Setters +namespace Lamar.IoC.Setters; + +/// +/// Establishes a test of whether a property should be "settable" in +/// object construction +/// +public interface ISetterPolicy : ILamarPolicy { - /// - /// Establishes a test of whether a property should be "settable" in - /// object construction - /// - public interface ISetterPolicy : ILamarPolicy - { - bool Matches(PropertyInfo prop); - } + bool Matches(PropertyInfo prop); } \ No newline at end of file diff --git a/src/Lamar/IoC/Setters/InjectedSetter.cs b/src/Lamar/IoC/Setters/InjectedSetter.cs index 9f0c78bb..436ef323 100644 --- a/src/Lamar/IoC/Setters/InjectedSetter.cs +++ b/src/Lamar/IoC/Setters/InjectedSetter.cs @@ -1,52 +1,48 @@ -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using Lamar.IoC.Frames; -using Lamar.IoC.Instances; using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; +using Lamar.IoC.Frames; +using Lamar.IoC.Instances; -namespace Lamar.IoC.Setters -{ +namespace Lamar.IoC.Setters; - internal class InjectedSetter +internal class InjectedSetter +{ + public InjectedSetter(PropertyInfo property, Instance instance) { - public PropertyInfo Property { get; } - public Instance Instance { get; } + Property = property; + Instance = instance; + } - public InjectedSetter(PropertyInfo property, Instance instance) - { - Property = property; - Instance = instance; - } + public PropertyInfo Property { get; } + public Instance Instance { get; } - public void ApplyQuickBuildProperties(object service, Scope scope) - { - var value = Instance.QuickResolve(scope); - Property.SetValue(service, value); - } + public void ApplyQuickBuildProperties(object service, Scope scope) + { + var value = Instance.QuickResolve(scope); + Property.SetValue(service, value); + } - public SetterArg Resolve(ResolverVariables variables, BuildMode mode) + public SetterArg Resolve(ResolverVariables variables, BuildMode mode) + { + Variable variable; + if (Instance.IsInlineDependency()) { - Variable variable; - if (Instance.IsInlineDependency()) - { - variable = Instance.CreateInlineVariable(variables); - - // HOKEY. Might need some smarter way of doing this. Helps to disambiguate - // between ctor args of nested decorators - if (!(variable is Setter)) - { - variable.OverrideName(variable.Usage + "_inline_" + ++variables.VariableSequence); - } - } - else + variable = Instance.CreateInlineVariable(variables); + + // HOKEY. Might need some smarter way of doing this. Helps to disambiguate + // between ctor args of nested decorators + if (!(variable is Setter)) { - variable = variables.Resolve(Instance, mode); + variable.OverrideName(variable.Usage + "_inline_" + ++variables.VariableSequence); } - - return new SetterArg(Property, variable); } + else + { + variable = variables.Resolve(Instance, mode); + } + + return new SetterArg(Property, variable); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Setters/LambdaSetterPolicy.cs b/src/Lamar/IoC/Setters/LambdaSetterPolicy.cs index 8f258d40..700b8d64 100644 --- a/src/Lamar/IoC/Setters/LambdaSetterPolicy.cs +++ b/src/Lamar/IoC/Setters/LambdaSetterPolicy.cs @@ -1,23 +1,22 @@ using System; using System.Reflection; -namespace Lamar.IoC.Setters +namespace Lamar.IoC.Setters; + +/// +/// Setter policy using a lambda test +/// +public class LambdaSetterPolicy : ISetterPolicy { - /// - /// Setter policy using a lambda test - /// - public class LambdaSetterPolicy : ISetterPolicy - { - private readonly Func _match; + private readonly Func _match; - public LambdaSetterPolicy(Func match) - { - _match = match; - } + public LambdaSetterPolicy(Func match) + { + _match = match; + } - public bool Matches(PropertyInfo prop) - { - return _match(prop); - } + public bool Matches(PropertyInfo prop) + { + return _match(prop); } } \ No newline at end of file diff --git a/src/Lamar/IoC/Setters/SetterConvention.cs b/src/Lamar/IoC/Setters/SetterConvention.cs index 784a63b5..66bd0718 100644 --- a/src/Lamar/IoC/Setters/SetterConvention.cs +++ b/src/Lamar/IoC/Setters/SetterConvention.cs @@ -1,84 +1,80 @@ using System; using System.Reflection; using JasperFx.Core.Reflection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.IoC.Setters -{ - /// - /// Used as an expression builder to specify setter injection policies - /// - public class SetterConvention - { - private readonly ServiceRegistry.PoliciesExpression _parent; - - public SetterConvention(ServiceRegistry.PoliciesExpression parent) - { - _parent = parent; - } +namespace Lamar.IoC.Setters; +/// +/// Used as an expression builder to specify setter injection policies +/// +public class SetterConvention +{ + private readonly ServiceRegistry.PoliciesExpression _parent; - /// - /// Directs StructureMap to treat all public setters of type T as - /// mandatory properties - /// - /// - public void OfType() - { - Matching(prop => prop.PropertyType == typeof (T)); - } + public SetterConvention(ServiceRegistry.PoliciesExpression parent) + { + _parent = parent; + } - /// - /// Directs StructureMap to tread all public setters with - /// a PropertyType that matches the predicate as a - /// mandatory setter - /// - /// - public void TypeMatches(Predicate predicate) - { - Matching(prop => predicate(prop.PropertyType)); - } - /// - /// Directs StructureMap to treat all public setters that match the - /// rule as mandatory properties - /// - /// - public void Matching(Func rule) - { - _parent.Add(new LambdaSetterPolicy(rule)); - } + /// + /// Directs StructureMap to treat all public setters of type T as + /// mandatory properties + /// + /// + public void OfType() + { + Matching(prop => prop.PropertyType == typeof(T)); + } - /// - /// Directs StructureMap to treat all public setters with a property - /// type in the specified namespace as mandatory properties - /// - /// - public void WithAnyTypeFromNamespace(string nameSpace) - { - Matching(prop => prop.PropertyType.IsInNamespace(nameSpace)); - } + /// + /// Directs StructureMap to tread all public setters with + /// a PropertyType that matches the predicate as a + /// mandatory setter + /// + /// + public void TypeMatches(Predicate predicate) + { + Matching(prop => predicate(prop.PropertyType)); + } - /// - /// Directs StructureMap to treat all public setters with a property - /// type in the specified namespace as mandatory properties - /// - /// - public void WithAnyTypeFromNamespaceContainingType() - { - WithAnyTypeFromNamespace(typeof (T).Namespace); - } + /// + /// Directs StructureMap to treat all public setters that match the + /// rule as mandatory properties + /// + /// + public void Matching(Func rule) + { + _parent.Add(new LambdaSetterPolicy(rule)); + } - /// - /// Directs StructureMap to treat all public setters where to property name - /// matches the specified rule as a mandatory property - /// - /// - public void NameMatches(Predicate rule) - { - Matching(prop => rule(prop.Name)); - } + /// + /// Directs StructureMap to treat all public setters with a property + /// type in the specified namespace as mandatory properties + /// + /// + public void WithAnyTypeFromNamespace(string nameSpace) + { + Matching(prop => prop.PropertyType.IsInNamespace(nameSpace)); + } + /// + /// Directs StructureMap to treat all public setters with a property + /// type in the specified namespace as mandatory properties + /// + /// + public void WithAnyTypeFromNamespaceContainingType() + { + WithAnyTypeFromNamespace(typeof(T).Namespace); + } + /// + /// Directs StructureMap to treat all public setters where to property name + /// matches the specified rule as a mandatory property + /// + /// + public void NameMatches(Predicate rule) + { + Matching(prop => rule(prop.Name)); } } \ No newline at end of file diff --git a/src/Lamar/IoC/StringExtensions.cs b/src/Lamar/IoC/StringExtensions.cs index ec849114..a1148804 100644 --- a/src/Lamar/IoC/StringExtensions.cs +++ b/src/Lamar/IoC/StringExtensions.cs @@ -1,12 +1,11 @@ using System.Text.RegularExpressions; -namespace Lamar.IoC +namespace Lamar.IoC; + +internal static class StringExtensions { - internal static class StringExtensions + public static string Sanitize(this string value) { - public static string Sanitize(this string value) - { - return Regex.Replace(value, @"[\#\<\>\,\.\]\[\`\+\-]", "_").Replace(" ", ""); - } + return Regex.Replace(value, @"[\#\<\>\,\.\]\[\`\+\-]", "_").Replace(" ", ""); } } \ No newline at end of file diff --git a/src/Lamar/Lamar.csproj b/src/Lamar/Lamar.csproj index c4c1d6ee..2611a31e 100644 --- a/src/Lamar/Lamar.csproj +++ b/src/Lamar/Lamar.csproj @@ -1,33 +1,32 @@  - - Fast ASP.Net Core compatible IoC Tool, Successor to StructureMap - 11.1.4 - Jeremy D. Miller - net6.0;net7.0 - portable - Lamar - Lamar - https://avatars2.githubusercontent.com/u/10048186?v=3&s=200 - http://jasperfx.github.io/lamar - https://github.com/JasperFX/lamar/blob/master/LICENSE - false - false - false - false - false - 10.0 - - - - - - - - + + Fast ASP.Net Core compatible IoC Tool, Successor to StructureMap + 12.0.0 + Jeremy D. Miller + net6.0;net7.0 + portable + Lamar + Lamar + https://avatars2.githubusercontent.com/u/10048186?v=3&s=200 + http://jasperfx.github.io/lamar + https://github.com/JasperFX/lamar/blob/master/LICENSE + false + false + false + false + false + 10.0 + + + + + + - - - - + + + + + \ No newline at end of file diff --git a/src/Lamar/LamarAttribute.cs b/src/Lamar/LamarAttribute.cs index e7b70b30..55a6f914 100644 --- a/src/Lamar/LamarAttribute.cs +++ b/src/Lamar/LamarAttribute.cs @@ -1,30 +1,30 @@ using System; using Lamar.IoC.Instances; -namespace Lamar +namespace Lamar; + +#region sample_LamarAttribute + +/// +/// Base class for custom configuration attributes +/// +public abstract class LamarAttribute : Attribute { - #region sample_LamarAttribute /// - /// Base class for custom configuration attributes + /// Make configuration alterations to a single IConfiguredInstance object /// - public abstract class LamarAttribute : Attribute + /// + public virtual void Alter(IConfiguredInstance instance) { - /// - /// Make configuration alterations to a single IConfiguredInstance object - /// - /// - public virtual void Alter(IConfiguredInstance instance) - { - } + } - /// - /// Make configuration changes to the most generic form of Instance - /// - /// - public virtual void Alter(Instance instance) - { - - } + /// + /// Make configuration changes to the most generic form of Instance + /// + /// + public virtual void Alter(Instance instance) + { } - #endregion -} \ No newline at end of file +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/LamarIgnoreAttribute.cs b/src/Lamar/LamarIgnoreAttribute.cs index 7a590d79..0d95e5c0 100644 --- a/src/Lamar/LamarIgnoreAttribute.cs +++ b/src/Lamar/LamarIgnoreAttribute.cs @@ -1,13 +1,11 @@ using System; -namespace Lamar +namespace Lamar; + +/// +/// Use to direct Lamar type scanning to ignore this type +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] +public class LamarIgnoreAttribute : Attribute { - /// - /// Use to direct Lamar type scanning to ignore this type - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] - public class LamarIgnoreAttribute : Attribute - { - - } } \ No newline at end of file diff --git a/src/Lamar/NamedAttribute.cs b/src/Lamar/NamedAttribute.cs index 37a946bb..2c3955a9 100644 --- a/src/Lamar/NamedAttribute.cs +++ b/src/Lamar/NamedAttribute.cs @@ -1,23 +1,22 @@ using System; -namespace Lamar +namespace Lamar; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter)] +public class NamedAttribute : Attribute { - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter)] - public class NamedAttribute : Attribute + public NamedAttribute(string name) { - public string Name { get; } - public string TypeName { get; set; } - - public NamedAttribute(string name) - { - Name = name; - } + Name = name; + } - public NamedAttribute(string name, string typeName) - { - Name = name; - TypeName = typeName; - } + public NamedAttribute(string name, string typeName) + { + Name = name; + TypeName = typeName; } + + public string Name { get; } + public string TypeName { get; set; } } \ No newline at end of file diff --git a/src/Lamar/RegistrationExtensions.cs b/src/Lamar/RegistrationExtensions.cs index 1deb07f1..5e4dc4e5 100644 --- a/src/Lamar/RegistrationExtensions.cs +++ b/src/Lamar/RegistrationExtensions.cs @@ -1,22 +1,21 @@ using System; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +public static class RegistrationExtensions { - public static class RegistrationExtensions + /// + /// Apply service overrides to Lamar that will take priority regardless of the service ordering + /// otherwise. This is primarily meant for test automation scenarios + /// + /// + /// + public static void OverrideServices(this IServiceCollection services, Action overrides) { - /// - /// Apply service overrides to Lamar that will take priority regardless of the service ordering - /// otherwise. This is primarily meant for test automation scenarios - /// - /// - /// - public static void OverrideServices(this IServiceCollection services, Action overrides) - { - var overrideRegistry = new LamarOverrides(); - overrides(overrideRegistry.Overrides); + var overrideRegistry = new LamarOverrides(); + overrides(overrideRegistry.Overrides); - services.AddSingleton(overrideRegistry); - } + services.AddSingleton(overrideRegistry); } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/AssemblyLoader.cs b/src/Lamar/Scanning/Conventions/AssemblyLoader.cs index 884b6984..ca0650ad 100644 --- a/src/Lamar/Scanning/Conventions/AssemblyLoader.cs +++ b/src/Lamar/Scanning/Conventions/AssemblyLoader.cs @@ -1,12 +1,11 @@ using System.Reflection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +public static class AssemblyLoader { - public static class AssemblyLoader + public static Assembly ByName(string assemblyName) { - public static Assembly ByName(string assemblyName) - { - return Assembly.Load(new AssemblyName(assemblyName)); - } + return Assembly.Load(new AssemblyName(assemblyName)); } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/AssemblyScanner.cs b/src/Lamar/Scanning/Conventions/AssemblyScanner.cs index 1f2349c2..da7a76d7 100644 --- a/src/Lamar/Scanning/Conventions/AssemblyScanner.cs +++ b/src/Lamar/Scanning/Conventions/AssemblyScanner.cs @@ -6,316 +6,321 @@ using System.Threading.Tasks; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; -using JasperFx.CodeGeneration.Util; -using Lamar.Util; +using JasperFx.Core.TypeScanning; using Microsoft.Extensions.DependencyInjection; #pragma warning disable 1591 -[assembly:IgnoreAssembly] +[assembly: IgnoreAssembly] -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +[LamarIgnore] +public class AssemblyScanner : IAssemblyScanner { - [LamarIgnore] - public class AssemblyScanner : IAssemblyScanner - { - private readonly List _assemblies = new List(); - private readonly CompositeFilter _filter = new CompositeFilter(); - private readonly ServiceRegistry _parent; + private readonly List _assemblies = new(); + private readonly CompositeFilter _filter = new(); + private readonly ServiceRegistry _parent; + private bool _hasScanned; - public AssemblyScanner(ServiceRegistry parent) - { - _parent = parent; + public AssemblyScanner(ServiceRegistry parent) + { + _parent = parent; - Exclude(type => type.HasAttribute()); - } + Exclude(type => type.HasAttribute()); + } - public List Conventions { get; } = new List(); + public List Conventions { get; } = new(); - public Task TypeFinder { get; private set; } + public TypeSet TypeFinder { get; private set; } - public string Description { get; set; } + public string Description { get; set; } - public void Assembly(Assembly assembly) + public void Assembly(Assembly assembly) + { + if (!_assemblies.Contains(assembly)) { - if (!_assemblies.Contains(assembly)) - _assemblies.Add(assembly); + _assemblies.Add(assembly); } + } - public void Assembly(string assemblyName) - { - Assembly(AssemblyLoader.ByName(assemblyName)); - } + public void Assembly(string assemblyName) + { + Assembly(AssemblyLoader.ByName(assemblyName)); + } - public void Convention() where T : IRegistrationConvention, new() + public void Convention() where T : IRegistrationConvention, new() + { + var previous = Conventions.FirstOrDefault(scanner => scanner is T); + if (previous == null) { - var previous = Conventions.FirstOrDefault(scanner => scanner is T); - if (previous == null) - With(new T()); + With(new T()); } + } - public void AssemblyContainingType() - { - AssemblyContainingType(typeof(T)); - } + public void AssemblyContainingType() + { + AssemblyContainingType(typeof(T)); + } - public void AssemblyContainingType(Type type) - { - _assemblies.Add(type.GetTypeInfo().Assembly); - } + public void AssemblyContainingType(Type type) + { + _assemblies.Add(type.GetTypeInfo().Assembly); + } - public FindAllTypesFilter AddAllTypesOf() - { - return AddAllTypesOf(typeof(TServiceType), ServiceLifetime.Transient); - } + public FindAllTypesFilter AddAllTypesOf() + { + return AddAllTypesOf(typeof(TServiceType), ServiceLifetime.Transient); + } - public FindAllTypesFilter AddAllTypesOf(ServiceLifetime lifetime) - { - return AddAllTypesOf(typeof(TServiceType), lifetime); - } + public FindAllTypesFilter AddAllTypesOf(ServiceLifetime lifetime) + { + return AddAllTypesOf(typeof(TServiceType), lifetime); + } - public FindAllTypesFilter AddAllTypesOf(Type pluginType) - { - return AddAllTypesOf(pluginType, ServiceLifetime.Transient); - } + public FindAllTypesFilter AddAllTypesOf(Type pluginType) + { + return AddAllTypesOf(pluginType, ServiceLifetime.Transient); + } - public FindAllTypesFilter AddAllTypesOf(Type pluginType, ServiceLifetime lifetime) - { - var filter = new FindAllTypesFilter(pluginType, lifetime); - With(filter); + public FindAllTypesFilter AddAllTypesOf(Type pluginType, ServiceLifetime lifetime) + { + var filter = new FindAllTypesFilter(pluginType, lifetime); + With(filter); - return filter; - } + return filter; + } - public void Exclude(Func exclude) - { - _filter.Excludes += exclude; - } + public void Exclude(Func exclude) + { + _filter.Excludes += exclude; + } - public void ExcludeNamespace(string nameSpace) - { - Exclude(type => type.IsInNamespace(nameSpace)); - } + public void ExcludeNamespace(string nameSpace) + { + Exclude(type => type.IsInNamespace(nameSpace)); + } - public void ExcludeNamespaceContainingType() - { - ExcludeNamespace(typeof(T).Namespace); - } + public void ExcludeNamespaceContainingType() + { + ExcludeNamespace(typeof(T).Namespace); + } - public void Include(Func predicate) - { - _filter.Includes += predicate; - } + public void Include(Func predicate) + { + _filter.Includes += predicate; + } - public void IncludeNamespace(string nameSpace) - { - Include(type => type.IsInNamespace(nameSpace)); - } + public void IncludeNamespace(string nameSpace) + { + Include(type => type.IsInNamespace(nameSpace)); + } - public void IncludeNamespaceContainingType() - { - IncludeNamespace(typeof(T).Namespace); - } + public void IncludeNamespaceContainingType() + { + IncludeNamespace(typeof(T).Namespace); + } - public void ExcludeType() - { - Exclude(type => type == typeof(T)); - } + public void ExcludeType() + { + Exclude(type => type == typeof(T)); + } - public void With(IRegistrationConvention convention) - { - Conventions.Fill(convention); - } + public void With(IRegistrationConvention convention) + { + Conventions.Fill(convention); + } - public void WithDefaultConventions() - { - WithDefaultConventions(ServiceLifetime.Transient); - } + public void WithDefaultConventions() + { + WithDefaultConventions(ServiceLifetime.Transient); + } - public void WithDefaultConventions(ServiceLifetime lifetime) - { - var convention = new DefaultConventionScanner(lifetime); - With(convention); - } + public void WithDefaultConventions(ServiceLifetime lifetime) + { + var convention = new DefaultConventionScanner(lifetime); + With(convention); + } - public void WithDefaultConventions(OverwriteBehavior behavior) - { - WithDefaultConventions(behavior, ServiceLifetime.Transient); - } + public void WithDefaultConventions(OverwriteBehavior behavior) + { + WithDefaultConventions(behavior, ServiceLifetime.Transient); + } - public void WithDefaultConventions(OverwriteBehavior behavior, ServiceLifetime lifetime) + public void WithDefaultConventions(OverwriteBehavior behavior, ServiceLifetime lifetime) + { + var convention = new DefaultConventionScanner(lifetime) { - var convention = new DefaultConventionScanner(lifetime) - { - Overwrites = behavior - }; + Overwrites = behavior + }; - With(convention); - } + With(convention); + } - public void ConnectImplementationsToTypesClosing(Type openGenericType) - { - ConnectImplementationsToTypesClosing(openGenericType, ServiceLifetime.Transient); - } + public void ConnectImplementationsToTypesClosing(Type openGenericType) + { + ConnectImplementationsToTypesClosing(openGenericType, ServiceLifetime.Transient); + } - public void ConnectImplementationsToTypesClosing(Type openGenericType, ServiceLifetime lifetime) - { - var convention = new GenericConnectionScanner(openGenericType, lifetime); - With(convention); - } + public void ConnectImplementationsToTypesClosing(Type openGenericType, ServiceLifetime lifetime) + { + var convention = new GenericConnectionScanner(openGenericType, lifetime); + With(convention); + } - public void RegisterConcreteTypesAgainstTheFirstInterface() - { - RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime.Transient); - } + public void RegisterConcreteTypesAgainstTheFirstInterface() + { + RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime.Transient); + } - public void RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime lifetime) - { - var convention = new FirstInterfaceConvention(lifetime); - With(convention); - } + public void RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime lifetime) + { + var convention = new FirstInterfaceConvention(lifetime); + With(convention); + } - public void SingleImplementationsOfInterface() - { - SingleImplementationsOfInterface(ServiceLifetime.Transient); - } + public void SingleImplementationsOfInterface() + { + SingleImplementationsOfInterface(ServiceLifetime.Transient); + } - public void SingleImplementationsOfInterface(ServiceLifetime lifetime) - { - var convention = new ImplementationMap(lifetime); - With(convention); - } + public void SingleImplementationsOfInterface(ServiceLifetime lifetime) + { + var convention = new ImplementationMap(lifetime); + With(convention); + } - public void LookForRegistries() - { - Convention(); - } + public void LookForRegistries() + { + Convention(); + } - public void TheCallingAssembly() + public void TheCallingAssembly() + { + if (_parent.GetType().Assembly != typeof(ServiceRegistry).Assembly) { - if (_parent.GetType().Assembly != typeof(ServiceRegistry).Assembly) - { - Assembly(_parent.GetType().Assembly); - return; - } - - var callingAssembly = CallingAssembly.Find(); - - if (callingAssembly != null) - Assembly(callingAssembly); - else - throw new InvalidOperationException( - "Could not determine the calling assembly, you may need to explicitly call IAssemblyScanner.Assembly()"); + Assembly(_parent.GetType().Assembly); + return; } - public void AssembliesFromApplicationBaseDirectory() + var callingAssembly = CallingAssembly.Find(); + + if (callingAssembly != null) { - AssembliesFromApplicationBaseDirectory(a => true); + Assembly(callingAssembly); } - - public void AssembliesFromApplicationBaseDirectory(Func assemblyFilter) + else { - var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter); - - foreach (var assembly in assemblies) Assembly(assembly); + throw new InvalidOperationException( + "Could not determine the calling assembly, you may need to explicitly call IAssemblyScanner.Assembly()"); } + } - /// - /// Choosing option will direct Jasper to *also* scan files ending in '*.exe' - /// - /// - /// - /// - public void AssembliesAndExecutablesFromApplicationBaseDirectory(Func assemblyFilter = null) - { - var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, true); + public void AssembliesFromApplicationBaseDirectory() + { + AssembliesFromApplicationBaseDirectory(a => true); + } - foreach (var assembly in assemblies) Assembly(assembly); - } + public void AssembliesFromApplicationBaseDirectory(Func assemblyFilter) + { + var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter); - [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] - public void AssembliesAndExecutablesFromPath(string path) - { - var assemblies = AssemblyFinder.FindAssemblies(a => true, path, - txt => - { - Console.WriteLine("Lamar could not load assembly from file " + txt); - }, true); + foreach (var assembly in assemblies) Assembly(assembly); + } - foreach (var assembly in assemblies) Assembly(assembly); - } + /// + /// Choosing option will direct Jasper to *also* scan files ending in '*.exe' + /// + /// + /// + /// + public void AssembliesAndExecutablesFromApplicationBaseDirectory(Func assemblyFilter = null) + { + var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, true); - [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] - public void AssembliesFromPath(string path) - { - var assemblies = AssemblyFinder.FindAssemblies(a => true, path, - txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, false); + foreach (var assembly in assemblies) Assembly(assembly); + } - foreach (var assembly in assemblies) Assembly(assembly); - } + [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] + public void AssembliesAndExecutablesFromPath(string path) + { + var assemblies = AssemblyFinder.FindAssemblies(a => true, path, + txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, true); - public void AssembliesAndExecutablesFromPath(string path, - Func assemblyFilter) - { - var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, path, - txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, true); + foreach (var assembly in assemblies) Assembly(assembly); + } + [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] + public void AssembliesFromPath(string path) + { + var assemblies = AssemblyFinder.FindAssemblies(a => true, path, + txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, false); - foreach (var assembly in assemblies) Assembly(assembly); - } + foreach (var assembly in assemblies) Assembly(assembly); + } - public void AssembliesFromPath(string path, - Func assemblyFilter) - { - var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, path, - txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, false); + public void AssembliesAndExecutablesFromPath(string path, + Func assemblyFilter) + { + var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, path, + txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, true); - foreach (var assembly in assemblies) Assembly(assembly); - } + foreach (var assembly in assemblies) Assembly(assembly); + } - public void Describe(StringWriter writer) - { - writer.WriteLine(Description); - writer.WriteLine("Assemblies"); - writer.WriteLine("----------"); + public void AssembliesFromPath(string path, + Func assemblyFilter) + { + var assemblies = AssemblyFinder.FindAssemblies(assemblyFilter, path, + txt => { Console.WriteLine("Lamar could not load assembly from file " + txt); }, false); - _assemblies.OrderBy(x => x.FullName).Each(x => writer.WriteLine("* " + x)); - writer.WriteLine(); - writer.WriteLine("Conventions"); - writer.WriteLine("--------"); - Conventions.Each(x => writer.WriteLine("* " + x)); - } + foreach (var assembly in assemblies) Assembly(assembly); + } - public void Start() - { - if (!Conventions.Any()) - throw new InvalidOperationException( - $"There are no {nameof(IRegistrationConvention)}'s in this scanning operation. "); + public void Describe(StringWriter writer) + { + writer.WriteLine(Description); + writer.WriteLine("Assemblies"); + writer.WriteLine("----------"); - TypeFinder = TypeRepository.FindTypes(_assemblies, type => _filter.Matches(type)); - } + _assemblies.OrderBy(x => x.FullName).Each(x => writer.WriteLine("* " + x)); + writer.WriteLine(); - public void ApplyRegistrations(ServiceRegistry services) - { - foreach (var convention in Conventions) - { - convention.ScanTypes(TypeFinder.Result, services); - } - } + writer.WriteLine("Conventions"); + writer.WriteLine("--------"); + Conventions.Each(x => writer.WriteLine("* " + x)); + } - public bool Contains(string assemblyName) + public void Start() + { + if (_hasScanned) return; + _hasScanned = true; + + if (!Conventions.Any()) { - return _assemblies - .Select(assembly => new AssemblyName(assembly.FullName)) - .Any(aName => aName.Name == assemblyName); + throw new InvalidOperationException( + $"There are no {nameof(IRegistrationConvention)}'s in this scanning operation. "); } + + TypeFinder = TypeRepository.FindTypes(_assemblies, type => _filter.Matches(type)); + } + + public void ApplyRegistrations(ServiceRegistry services) + { + foreach (var convention in Conventions) convention.ScanTypes(TypeFinder, services); + } + + public bool Contains(string assemblyName) + { + return _assemblies + .Select(assembly => new AssemblyName(assembly.FullName)) + .Any(aName => aName.Name == assemblyName); } } diff --git a/src/Lamar/Scanning/Conventions/DefaultConventionScanner.cs b/src/Lamar/Scanning/Conventions/DefaultConventionScanner.cs index 10952f0c..a3f435fc 100644 --- a/src/Lamar/Scanning/Conventions/DefaultConventionScanner.cs +++ b/src/Lamar/Scanning/Conventions/DefaultConventionScanner.cs @@ -1,56 +1,66 @@ using System; using System.Linq; using System.Reflection; -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal class DefaultConventionScanner : IRegistrationConvention { - internal class DefaultConventionScanner : IRegistrationConvention - { - private readonly ServiceLifetime _lifetime; + private readonly ServiceLifetime _lifetime; - public DefaultConventionScanner(ServiceLifetime lifetime = ServiceLifetime.Transient) - { - _lifetime = lifetime; - } + public DefaultConventionScanner(ServiceLifetime lifetime = ServiceLifetime.Transient) + { + _lifetime = lifetime; + } - public OverwriteBehavior Overwrites { get; set; } = OverwriteBehavior.NewType; + public OverwriteBehavior Overwrites { get; set; } = OverwriteBehavior.NewType; - public void ScanTypes(TypeSet types, ServiceRegistry services) + public void ScanTypes(TypeSet types, ServiceRegistry services) + { + foreach (var type in types.FindTypes(TypeClassification.Concretes) + .Where(type => type.GetConstructors().Any())) { - foreach (var type in types.FindTypes(TypeClassification.Concretes) - .Where(type => type.GetConstructors().Any())) + var serviceType = FindServiceType(type); + if (serviceType != null && ShouldAdd(services, serviceType, type)) { - var serviceType = FindServiceType(type); - if (serviceType != null && ShouldAdd(services, serviceType, type)) - services.Add(new ServiceDescriptor(serviceType, type, _lifetime)); + services.Add(new ServiceDescriptor(serviceType, type, _lifetime)); } } + } - public bool ShouldAdd(IServiceCollection services, Type serviceType, Type implementationType) + public bool ShouldAdd(IServiceCollection services, Type serviceType, Type implementationType) + { + if (Overwrites == OverwriteBehavior.Always) { - if (Overwrites == OverwriteBehavior.Always) return true; - - var matches = services.Where(x => x.ServiceType == serviceType).ToArray(); - if (!matches.Any()) return true; - - if (Overwrites == OverwriteBehavior.Never) return false; - - var hasMatch = matches.Any(x => x.Matches(serviceType, implementationType)); - - return !hasMatch; + return true; } - public virtual Type FindServiceType(Type concreteType) + var matches = services.Where(x => x.ServiceType == serviceType).ToArray(); + if (!matches.Any()) { - var interfaceName = "I" + concreteType.Name; - return concreteType.GetTypeInfo().GetInterfaces().FirstOrDefault(t => t.Name == interfaceName); + return true; } - public override string ToString() + if (Overwrites == OverwriteBehavior.Never) { - return "Default I[Name]/[Name] registration convention"; + return false; } + + var hasMatch = matches.Any(x => x.Matches(serviceType, implementationType)); + + return !hasMatch; + } + + public virtual Type FindServiceType(Type concreteType) + { + var interfaceName = "I" + concreteType.Name; + return concreteType.GetTypeInfo().GetInterfaces().FirstOrDefault(t => t.Name == interfaceName); + } + + public override string ToString() + { + return "Default I[Name]/[Name] registration convention"; } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/FindAllTypesFilter.cs b/src/Lamar/Scanning/Conventions/FindAllTypesFilter.cs index 69ef5912..f5606462 100644 --- a/src/Lamar/Scanning/Conventions/FindAllTypesFilter.cs +++ b/src/Lamar/Scanning/Conventions/FindAllTypesFilter.cs @@ -2,66 +2,68 @@ using System.Linq; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +public class FindAllTypesFilter : IRegistrationConvention { - public class FindAllTypesFilter : IRegistrationConvention + private readonly ServiceLifetime _lifetime; + private readonly Type _serviceType; + private Func _namePolicy = type => type.NameInCode(); + + public FindAllTypesFilter(Type serviceType, ServiceLifetime lifetime = ServiceLifetime.Transient) { - private readonly Type _serviceType; - private Func _namePolicy = type => type.NameInCode(); - private readonly ServiceLifetime _lifetime; + _serviceType = serviceType; + _lifetime = lifetime; + } - public FindAllTypesFilter(Type serviceType, ServiceLifetime lifetime = ServiceLifetime.Transient) + void IRegistrationConvention.ScanTypes(TypeSet types, ServiceRegistry services) + { + if (_serviceType.IsOpenGeneric()) { - _serviceType = serviceType; - _lifetime = lifetime; + var scanner = new GenericConnectionScanner(_serviceType, _lifetime); + scanner.ScanTypes(types, services); } - - void IRegistrationConvention.ScanTypes(TypeSet types, ServiceRegistry services) + else { - if (_serviceType.IsOpenGeneric()) - { - var scanner = new GenericConnectionScanner(_serviceType, _lifetime); - scanner.ScanTypes(types, services); - } - else + types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(Matches).Each(type => { - types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(Matches).Each(type => + var serviceType = determineLeastSpecificButValidType(_serviceType, type); + var instance = services.AddType(serviceType, type, _lifetime); + if (instance != null) { - var serviceType = determineLeastSpecificButValidType(_serviceType, type); - var instance = services.AddType(serviceType, type, _lifetime); - if (instance != null) instance.Name = _namePolicy(type); - }); - } + instance.Name = _namePolicy(type); + } + }); } + } - private bool Matches(Type type) - { - return Instance.CanBeCastTo(type, _serviceType) && type.GetConstructors().Any() && type.CanBeCreated(); - } + private bool Matches(Type type) + { + return Instance.CanBeCastTo(type, _serviceType) && type.GetConstructors().Any() && type.CanBeCreated(); + } - private static Type determineLeastSpecificButValidType(Type pluginType, Type type) + private static Type determineLeastSpecificButValidType(Type pluginType, Type type) + { + if (pluginType.IsGenericTypeDefinition && !type.IsOpenGeneric()) { - if (pluginType.IsGenericTypeDefinition && !type.IsOpenGeneric()) - return type.FindFirstInterfaceThatCloses(pluginType); - - return pluginType; + return type.FindFirstInterfaceThatCloses(pluginType); } - public override string ToString() - { - return "Find and register all types implementing " + _serviceType.FullName; - } + return pluginType; + } - public FindAllTypesFilter NameBy(Func namePolicy) - { - _namePolicy = namePolicy; - return this; - } + public override string ToString() + { + return "Find and register all types implementing " + _serviceType.FullName; + } + + public FindAllTypesFilter NameBy(Func namePolicy) + { + _namePolicy = namePolicy; + return this; } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/FindRegistriesScanner.cs b/src/Lamar/Scanning/Conventions/FindRegistriesScanner.cs index 108f8b0d..33721515 100644 --- a/src/Lamar/Scanning/Conventions/FindRegistriesScanner.cs +++ b/src/Lamar/Scanning/Conventions/FindRegistriesScanner.cs @@ -3,34 +3,41 @@ using System.Reflection; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.TypeScanning; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal class FindRegistriesScanner : IRegistrationConvention { - internal class FindRegistriesScanner : IRegistrationConvention + public void ScanTypes(TypeSet types, ServiceRegistry registry) { - public void ScanTypes(TypeSet types, ServiceRegistry registry) + types.FindTypes(TypeClassification.Closed | TypeClassification.Concretes) + .Where(IsPublicRegistry) + .Each(type => + { + var found = Activator.CreateInstance(type).As(); + registry.IncludeRegistry(found); + }); + } + + internal static bool IsPublicRegistry(Type type) + { + var ti = type.GetTypeInfo(); + if (Equals(ti.Assembly, typeof(ServiceRegistry).GetTypeInfo().Assembly)) { - types.FindTypes(TypeClassification.Closed | TypeClassification.Concretes) - .Where(IsPublicRegistry) - .Each(type => - { - var found = Activator.CreateInstance(type).As(); - registry.IncludeRegistry(found); - }); + return false; } - internal static bool IsPublicRegistry(Type type) + if (!typeof(ServiceRegistry).GetTypeInfo().IsAssignableFrom(ti)) { - var ti = type.GetTypeInfo(); - if (Equals(ti.Assembly, typeof(ServiceRegistry).GetTypeInfo().Assembly)) return false; - - if (!typeof(ServiceRegistry).GetTypeInfo().IsAssignableFrom(ti)) return false; - - if (ti.IsInterface || ti.IsAbstract || ti.IsGenericType) return false; + return false; + } - return type.GetConstructor(new Type[0]) != null; + if (ti.IsInterface || ti.IsAbstract || ti.IsGenericType) + { + return false; } + + return type.GetConstructor(new Type[0]) != null; } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/FirstInterfaceConvention.cs b/src/Lamar/Scanning/Conventions/FirstInterfaceConvention.cs index 8fee55b6..9b9583f1 100644 --- a/src/Lamar/Scanning/Conventions/FirstInterfaceConvention.cs +++ b/src/Lamar/Scanning/Conventions/FirstInterfaceConvention.cs @@ -1,34 +1,35 @@ using System; using System.Linq; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.TypeScanning; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal class FirstInterfaceConvention : IRegistrationConvention { - internal class FirstInterfaceConvention : IRegistrationConvention - { - private readonly ServiceLifetime _lifetime; + private readonly ServiceLifetime _lifetime; - public FirstInterfaceConvention(ServiceLifetime lifetime = ServiceLifetime.Transient) - { - _lifetime = lifetime; - } + public FirstInterfaceConvention(ServiceLifetime lifetime = ServiceLifetime.Transient) + { + _lifetime = lifetime; + } - public void ScanTypes(TypeSet types, ServiceRegistry services) + public void ScanTypes(TypeSet types, ServiceRegistry services) + { + foreach (var type in types.FindTypes(TypeClassification.Concretes).Where(x => x.GetConstructors().Any())) { - foreach (var type in types.FindTypes(TypeClassification.Concretes).Where(x => x.GetConstructors().Any())) + var interfaceType = type.GetInterfaces().FirstOrDefault(x => x != typeof(IDisposable)); + if (interfaceType != null && !interfaceType.HasAttribute() && + !type.IsOpenGeneric()) { - var interfaceType = type.GetInterfaces().FirstOrDefault(x => x != typeof(IDisposable)); - if (interfaceType != null && !interfaceType.HasAttribute() && - !type.IsOpenGeneric()) services.AddType(interfaceType, type, _lifetime); + services.AddType(interfaceType, type, _lifetime); } } + } - public override string ToString() - { - return "Register all concrete types against the first interface (if any) that they implement"; - } + public override string ToString() + { + return "Register all concrete types against the first interface (if any) that they implement"; } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/GenericConnectionScanner.cs b/src/Lamar/Scanning/Conventions/GenericConnectionScanner.cs index 6f0b6368..8cf434d3 100644 --- a/src/Lamar/Scanning/Conventions/GenericConnectionScanner.cs +++ b/src/Lamar/Scanning/Conventions/GenericConnectionScanner.cs @@ -3,77 +3,86 @@ using System.Linq; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.TypeScanning; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal class GenericConnectionScanner : IRegistrationConvention { - internal class GenericConnectionScanner : IRegistrationConvention + private readonly IList _concretions = new List(); + private readonly IList _interfaces = new List(); + private readonly ServiceLifetime _lifetime; + private readonly Type _openType; + + public GenericConnectionScanner(Type openType, ServiceLifetime lifetime = ServiceLifetime.Transient) { - private readonly IList _concretions = new List(); - private readonly IList _interfaces = new List(); - private readonly Type _openType; - private readonly ServiceLifetime _lifetime; + _openType = openType; + _lifetime = lifetime; - public GenericConnectionScanner(Type openType, ServiceLifetime lifetime = ServiceLifetime.Transient) + if (!_openType.IsOpenGeneric()) { - _openType = openType; - _lifetime = lifetime; - - if (!_openType.IsOpenGeneric()) - throw new InvalidOperationException( - "This scanning convention can only be used with open generic types"); + throw new InvalidOperationException( + "This scanning convention can only be used with open generic types"); } + } - public void ScanTypes( - TypeSet types, ServiceRegistry services) + public void ScanTypes( + TypeSet types, ServiceRegistry services) + { + foreach (var type in types.AllTypes()) { - foreach (var type in types.AllTypes()) + var interfaceTypes = type.FindInterfacesThatClose(_openType).ToArray(); + if (!interfaceTypes.Any()) { - var interfaceTypes = type.FindInterfacesThatClose(_openType).ToArray(); - if (!interfaceTypes.Any()) continue; - - if (type.IsConcrete()) _concretions.Add(type); - - foreach (var interfaceType in interfaceTypes) _interfaces.Fill(interfaceType); + continue; } - - foreach (var @interface in _interfaces) + if (type.IsConcrete()) { - var exactMatches = _concretions.Where(x => x.CanBeCastTo(@interface)).ToArray(); - foreach (var type in exactMatches) services.Add(new ServiceDescriptor(@interface, type, _lifetime)); - - if (!@interface.IsOpenGeneric()) addConcretionsThatCouldBeClosed(@interface, services); + _concretions.Add(type); } - var concretions = services.ConnectedConcretions(); - foreach (var type in _concretions) concretions.Fill(type); + foreach (var interfaceType in interfaceTypes) _interfaces.Fill(interfaceType); } - public override string ToString() + + foreach (var @interface in _interfaces) { - return "Connect all implementations of open generic type " + _openType.FullNameInCode(); + var exactMatches = _concretions.Where(x => x.CanBeCastTo(@interface)).ToArray(); + foreach (var type in exactMatches) services.Add(new ServiceDescriptor(@interface, type, _lifetime)); + + if (!@interface.IsOpenGeneric()) + { + addConcretionsThatCouldBeClosed(@interface, services); + } } - private void addConcretionsThatCouldBeClosed(Type @interface, IServiceCollection services) - { - _concretions.Where(x => x.IsOpenGeneric()) - .Where(x => x.CouldCloseTo(@interface)) - .Each(type => + var concretions = services.ConnectedConcretions(); + foreach (var type in _concretions) concretions.Fill(type); + } + + public override string ToString() + { + return "Connect all implementations of open generic type " + _openType.FullNameInCode(); + } + + private void addConcretionsThatCouldBeClosed(Type @interface, IServiceCollection services) + { + _concretions.Where(x => x.IsOpenGeneric()) + .Where(x => x.CouldCloseTo(@interface)) + .Each(type => + { + try { - try - { - services.Add(new ServiceDescriptor(@interface, type.MakeGenericType(@interface.GetGenericArguments()), _lifetime)); - } - catch (Exception) - { - // Because I'm too lazy to fight with the bleeping type constraints to "know" - // if it's possible to make the generic type and this is just easier. - } - }); - } + services.Add(new ServiceDescriptor(@interface, + type.MakeGenericType(@interface.GetGenericArguments()), _lifetime)); + } + catch (Exception) + { + // Because I'm too lazy to fight with the bleeping type constraints to "know" + // if it's possible to make the generic type and this is just easier. + } + }); } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/IAssemblyScanner.cs b/src/Lamar/Scanning/Conventions/IAssemblyScanner.cs index 082d3e22..361b9295 100644 --- a/src/Lamar/Scanning/Conventions/IAssemblyScanner.cs +++ b/src/Lamar/Scanning/Conventions/IAssemblyScanner.cs @@ -1,233 +1,232 @@ -using Microsoft.Extensions.DependencyInjection; using System; using System.Reflection; +using Microsoft.Extensions.DependencyInjection; + +namespace Lamar.Scanning.Conventions; -namespace Lamar.Scanning.Conventions +public interface IAssemblyScanner { - public interface IAssemblyScanner - { - /// - /// Optional user-supplied diagnostic description of this scanning operation - /// - string Description { get; set; } - - /// - /// Add an Assembly to the scanning operation - /// - /// - void Assembly(Assembly assembly); - - /// - /// Add an Assembly by name to the scanning operation - /// - /// - void Assembly(string assemblyName); - - /// - /// Add the Assembly that contains type T to the scanning operation - /// - /// - void AssemblyContainingType(); - - /// - /// Add the Assembly that contains type to the scanning operation - /// - /// - void AssemblyContainingType(Type type); - - /// - /// Add all concrete types of the Service Type as Instances of Service Type - /// - /// - FindAllTypesFilter AddAllTypesOf(); - - /// - /// Add all concrete types of the Service Type as Instances of Service Type - /// with the specified lifetime - /// - /// - /// - FindAllTypesFilter AddAllTypesOf(ServiceLifetime lifetime); - - /// - /// Add all concrete types of the Service Type as Instances of Service Type - /// - /// - FindAllTypesFilter AddAllTypesOf(Type pluginType); - - /// - /// Add all concrete types of the Service Type as Instances of Service Type - /// with the specified lifetime - /// - /// - /// - FindAllTypesFilter AddAllTypesOf(Type pluginType, ServiceLifetime lifetime); - - /// - /// Exclude types that match the Predicate from being scanned - /// - /// - void Exclude(Func exclude); - - /// - /// Exclude all types in this nameSpace or its children from the scanning operation - /// - /// - void ExcludeNamespace(string nameSpace); - - /// - /// Exclude all types in this nameSpace or its children from the scanning operation - /// - /// - void ExcludeNamespaceContainingType(); - - /// - /// Only include types matching the Predicate in the scanning operation. You can - /// use multiple Include() calls in a single scanning operation - /// - /// - void Include(Func predicate); - - /// - /// Only include types from this nameSpace or its children in the scanning operation. You can - /// use multiple Include() calls in a single scanning operation - /// - /// - void IncludeNamespace(string nameSpace); - - /// - /// Only include types from this nameSpace or its children in the scanning operation. You can - /// use multiple Include() calls in a single scanning operation - /// - /// - void IncludeNamespaceContainingType(); - - /// - /// Exclude this specific type from the scanning operation - /// - /// - void ExcludeType(); - - /// - /// Adds a registration convention to be applied to all the types in this - /// logical "scan" operation - /// - /// - void Convention() where T : IRegistrationConvention, new(); - - /// - /// Adds a registration convention to be applied to all the types in this - /// logical "scan" operation - /// - void With(IRegistrationConvention convention); - - /// - /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete - /// class named "Something" that implements "ISomething" will be automatically - /// added to ServiceType "ISomething" - /// - void WithDefaultConventions(); - - /// - /// Adds the DefaultConventionScanner to the scanning operations with the specified lifetime. - /// I.e., a concrete class named "Something" that implements "ISomething" will be automatically - /// added to ServiceType "ISomething" - /// - /// - void WithDefaultConventions(ServiceLifetime lifetime); - - /// - /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete - /// class named "Something" that implements "ISomething" will be automatically - /// added to ServiceType "ISomething" - /// - /// Define whether or not Lamar should overwrite any existing registrations. Default is IfNew - void WithDefaultConventions(OverwriteBehavior behavior); - - /// - /// Adds the DefaultConventionScanner to the scanning operations with the specified lifetime. - /// I.e., a concrete class named "Something" that implements "ISomething" will be automatically - /// added to ServiceType "ISomething" - /// - /// Define whether or not Lamar should overwrite any existing registrations. Default is IfNew - /// The to use - void WithDefaultConventions(OverwriteBehavior behavior, ServiceLifetime lifetime); - - /// - /// Automatically registers all concrete types without primitive arguments - /// against its first interface, if any - /// - void RegisterConcreteTypesAgainstTheFirstInterface(); - - /// - /// Automatically registers all concrete types without primitive arguments - /// against its first interface, if any, using the specified lifetime - /// - /// - void RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime lifetime); - - /// - /// Directs the scanning to automatically register any type that is the single - /// implementation of an interface against that interface. - /// The filters apply - /// - void SingleImplementationsOfInterface(); - - /// - /// Directs the scanning to automatically register any type that is the single - /// implementation of an interface against that interface, using the specified lifetime. - /// The filters apply - /// - /// - void SingleImplementationsOfInterface(ServiceLifetime lifetime); - - void TheCallingAssembly(); - void AssembliesFromApplicationBaseDirectory(); - void AssembliesFromApplicationBaseDirectory(Func assemblyFilter); - - - /// - /// Scans for ServiceType's and Concrete Types that close the given open generic type - /// - /// - /// - /// - void ConnectImplementationsToTypesClosing(Type openGenericType); - - /// - /// Scans for ServiceType's and Concrete Types that close the given open generic type - /// - /// - /// - /// - /// - void ConnectImplementationsToTypesClosing(Type openGenericType, ServiceLifetime lifetime); - - /// - /// Choosing option will direct StructureMap to *also* scan files ending in '*.exe' - /// - /// - /// - /// - void AssembliesAndExecutablesFromApplicationBaseDirectory(Func assemblyFilter = null); - - [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] - void AssembliesAndExecutablesFromPath(string path); - - [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] - void AssembliesFromPath(string path); - - void AssembliesAndExecutablesFromPath(string path, - Func assemblyFilter); - - void AssembliesFromPath(string path, - Func assemblyFilter); - - - /// - /// Directs the scanning operation to automatically detect and include any Registry - /// classes found in the Assembly's being scanned - /// - void LookForRegistries(); - } + /// + /// Optional user-supplied diagnostic description of this scanning operation + /// + string Description { get; set; } + + /// + /// Add an Assembly to the scanning operation + /// + /// + void Assembly(Assembly assembly); + + /// + /// Add an Assembly by name to the scanning operation + /// + /// + void Assembly(string assemblyName); + + /// + /// Add the Assembly that contains type T to the scanning operation + /// + /// + void AssemblyContainingType(); + + /// + /// Add the Assembly that contains type to the scanning operation + /// + /// + void AssemblyContainingType(Type type); + + /// + /// Add all concrete types of the Service Type as Instances of Service Type + /// + /// + FindAllTypesFilter AddAllTypesOf(); + + /// + /// Add all concrete types of the Service Type as Instances of Service Type + /// with the specified lifetime + /// + /// + /// + FindAllTypesFilter AddAllTypesOf(ServiceLifetime lifetime); + + /// + /// Add all concrete types of the Service Type as Instances of Service Type + /// + /// + FindAllTypesFilter AddAllTypesOf(Type pluginType); + + /// + /// Add all concrete types of the Service Type as Instances of Service Type + /// with the specified lifetime + /// + /// + /// + FindAllTypesFilter AddAllTypesOf(Type pluginType, ServiceLifetime lifetime); + + /// + /// Exclude types that match the Predicate from being scanned + /// + /// + void Exclude(Func exclude); + + /// + /// Exclude all types in this nameSpace or its children from the scanning operation + /// + /// + void ExcludeNamespace(string nameSpace); + + /// + /// Exclude all types in this nameSpace or its children from the scanning operation + /// + /// + void ExcludeNamespaceContainingType(); + + /// + /// Only include types matching the Predicate in the scanning operation. You can + /// use multiple Include() calls in a single scanning operation + /// + /// + void Include(Func predicate); + + /// + /// Only include types from this nameSpace or its children in the scanning operation. You can + /// use multiple Include() calls in a single scanning operation + /// + /// + void IncludeNamespace(string nameSpace); + + /// + /// Only include types from this nameSpace or its children in the scanning operation. You can + /// use multiple Include() calls in a single scanning operation + /// + /// + void IncludeNamespaceContainingType(); + + /// + /// Exclude this specific type from the scanning operation + /// + /// + void ExcludeType(); + + /// + /// Adds a registration convention to be applied to all the types in this + /// logical "scan" operation + /// + /// + void Convention() where T : IRegistrationConvention, new(); + + /// + /// Adds a registration convention to be applied to all the types in this + /// logical "scan" operation + /// + void With(IRegistrationConvention convention); + + /// + /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete + /// class named "Something" that implements "ISomething" will be automatically + /// added to ServiceType "ISomething" + /// + void WithDefaultConventions(); + + /// + /// Adds the DefaultConventionScanner to the scanning operations with the specified lifetime. + /// I.e., a concrete class named "Something" that implements "ISomething" will be automatically + /// added to ServiceType "ISomething" + /// + /// + void WithDefaultConventions(ServiceLifetime lifetime); + + /// + /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete + /// class named "Something" that implements "ISomething" will be automatically + /// added to ServiceType "ISomething" + /// + /// Define whether or not Lamar should overwrite any existing registrations. Default is IfNew + void WithDefaultConventions(OverwriteBehavior behavior); + + /// + /// Adds the DefaultConventionScanner to the scanning operations with the specified lifetime. + /// I.e., a concrete class named "Something" that implements "ISomething" will be automatically + /// added to ServiceType "ISomething" + /// + /// Define whether or not Lamar should overwrite any existing registrations. Default is IfNew + /// The to use + void WithDefaultConventions(OverwriteBehavior behavior, ServiceLifetime lifetime); + + /// + /// Automatically registers all concrete types without primitive arguments + /// against its first interface, if any + /// + void RegisterConcreteTypesAgainstTheFirstInterface(); + + /// + /// Automatically registers all concrete types without primitive arguments + /// against its first interface, if any, using the specified lifetime + /// + /// + void RegisterConcreteTypesAgainstTheFirstInterface(ServiceLifetime lifetime); + + /// + /// Directs the scanning to automatically register any type that is the single + /// implementation of an interface against that interface. + /// The filters apply + /// + void SingleImplementationsOfInterface(); + + /// + /// Directs the scanning to automatically register any type that is the single + /// implementation of an interface against that interface, using the specified lifetime. + /// The filters apply + /// + /// + void SingleImplementationsOfInterface(ServiceLifetime lifetime); + + void TheCallingAssembly(); + void AssembliesFromApplicationBaseDirectory(); + void AssembliesFromApplicationBaseDirectory(Func assemblyFilter); + + + /// + /// Scans for ServiceType's and Concrete Types that close the given open generic type + /// + /// + /// + /// + void ConnectImplementationsToTypesClosing(Type openGenericType); + + /// + /// Scans for ServiceType's and Concrete Types that close the given open generic type + /// + /// + /// + /// + /// + void ConnectImplementationsToTypesClosing(Type openGenericType, ServiceLifetime lifetime); + + /// + /// Choosing option will direct StructureMap to *also* scan files ending in '*.exe' + /// + /// + /// + /// + void AssembliesAndExecutablesFromApplicationBaseDirectory(Func assemblyFilter = null); + + [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] + void AssembliesAndExecutablesFromPath(string path); + + [Obsolete("It is very strongly recommended to use the overload with an Assembly filter to improve performance")] + void AssembliesFromPath(string path); + + void AssembliesAndExecutablesFromPath(string path, + Func assemblyFilter); + + void AssembliesFromPath(string path, + Func assemblyFilter); + + + /// + /// Directs the scanning operation to automatically detect and include any Registry + /// classes found in the Assembly's being scanned + /// + void LookForRegistries(); } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/IRegistrationConvention.cs b/src/Lamar/Scanning/Conventions/IRegistrationConvention.cs index d179ea66..896aa6ba 100644 --- a/src/Lamar/Scanning/Conventions/IRegistrationConvention.cs +++ b/src/Lamar/Scanning/Conventions/IRegistrationConvention.cs @@ -1,15 +1,15 @@ -using JasperFx.TypeDiscovery; +using JasperFx.Core.TypeScanning; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +#region sample_IRegistrationConvention + +/// +/// Used to create custom type scanning conventions +/// +public interface IRegistrationConvention { - #region sample_IRegistrationConvention - /// - /// Used to create custom type scanning conventions - /// - public interface IRegistrationConvention - { - void ScanTypes(TypeSet types, ServiceRegistry services); - } - - #endregion -} \ No newline at end of file + void ScanTypes(TypeSet types, ServiceRegistry services); +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/ImplementationMap.cs b/src/Lamar/Scanning/Conventions/ImplementationMap.cs index b4f628bc..2d719807 100644 --- a/src/Lamar/Scanning/Conventions/ImplementationMap.cs +++ b/src/Lamar/Scanning/Conventions/ImplementationMap.cs @@ -2,38 +2,39 @@ using System.Linq; using JasperFx.Core; using JasperFx.Core.Reflection; -using JasperFx.TypeDiscovery; -using JasperFx.CodeGeneration.Util; +using JasperFx.Core.TypeScanning; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal class ImplementationMap : IRegistrationConvention { - internal class ImplementationMap : IRegistrationConvention + private readonly ServiceLifetime _lifetime; + + public ImplementationMap(ServiceLifetime lifetime = ServiceLifetime.Transient) { - private readonly ServiceLifetime _lifetime; + _lifetime = lifetime; + } - public ImplementationMap(ServiceLifetime lifetime = ServiceLifetime.Transient) - { - _lifetime = lifetime; - } + public void ScanTypes(TypeSet types, ServiceRegistry services) + { + var interfaces = types.FindTypes(TypeClassification.Interfaces | TypeClassification.Closed) + .Where(x => x != typeof(IDisposable)); + var concretes = types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed) + .Where(x => x.GetConstructors().Any()).ToArray(); - public void ScanTypes(TypeSet types, ServiceRegistry services) + interfaces.Each(@interface => { - var interfaces = types.FindTypes(TypeClassification.Interfaces | TypeClassification.Closed) - .Where(x => x != typeof(IDisposable)); - var concretes = types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed) - .Where(x => x.GetConstructors().Any()).ToArray(); - - interfaces.Each(@interface => + var implementors = concretes.Where(x => x.CanBeCastTo(@interface)).ToArray(); + if (implementors.Count() == 1) { - var implementors = concretes.Where(x => x.CanBeCastTo(@interface)).ToArray(); - if (implementors.Count() == 1) services.Add(new ServiceDescriptor(@interface, implementors.Single(), _lifetime)); - }); - } + services.Add(new ServiceDescriptor(@interface, implementors.Single(), _lifetime)); + } + }); + } - public override string ToString() - { - return "Register any single implementation of any interface against that interface"; - } + public override string ToString() + { + return "Register any single implementation of any interface against that interface"; } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/OverwriteBehavior.cs b/src/Lamar/Scanning/Conventions/OverwriteBehavior.cs index 3f1a1950..170e51c5 100644 --- a/src/Lamar/Scanning/Conventions/OverwriteBehavior.cs +++ b/src/Lamar/Scanning/Conventions/OverwriteBehavior.cs @@ -1,25 +1,24 @@ -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +/// +/// Controls the behavior of the type scanning registrations if there are prior, matching +/// registrations +/// +public enum OverwriteBehavior { /// - /// Controls the behavior of the type scanning registrations if there are prior, matching - /// registrations + /// Add registrations for the service type even if there are other registrations + /// for this service type /// - public enum OverwriteBehavior - { - /// - /// Add registrations for the service type even if there are other registrations - /// for this service type - /// - Always, + Always, - /// - /// Add registrations if the service type/implementation type is new - /// - NewType, + /// + /// Add registrations if the service type/implementation type is new + /// + NewType, - /// - /// Do not add any registrations for the service type if there are any other registrations - /// - Never - } + /// + /// Do not add any registrations for the service type if there are any other registrations + /// + Never } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/ScanningExploder.cs b/src/Lamar/Scanning/Conventions/ScanningExploder.cs index 14693a68..3105bcfe 100644 --- a/src/Lamar/Scanning/Conventions/ScanningExploder.cs +++ b/src/Lamar/Scanning/Conventions/ScanningExploder.cs @@ -4,116 +4,130 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal static class ScanningExploder { - internal static class ScanningExploder + internal static (ServiceRegistry, AssemblyScanner[]) ExplodeSynchronously(IServiceCollection services) { - internal static (ServiceRegistry, AssemblyScanner[]) ExplodeSynchronously(IServiceCollection services) - { - var scanners = new AssemblyScanner[0]; - var registry = new ServiceRegistry(services); + var scanners = new AssemblyScanner[0]; + var registry = new ServiceRegistry(services); - var registriesEncountered = new List(); + var registriesEncountered = new List(); - while (registry.HasScanners()) - { - var (registry2, operations) = ParseToOperations(registry, registriesEncountered); + while (registry.HasScanners()) + { + var (registry2, operations) = ParseToOperations(registry, registriesEncountered); - var additional = operations.OfType().ToArray(); + var additional = operations.OfType().ToArray(); - registry = registry2; - scanners = scanners.Concat(additional).ToArray(); + registry = registry2; + scanners = scanners.Concat(additional).ToArray(); - registry.RemoveAll(x => x.ServiceType == typeof(AssemblyScanner)); + registry.RemoveAll(x => x.ServiceType == typeof(AssemblyScanner)); - Task.WhenAll(additional.Select(x => x.TypeFinder)).Wait(TimeSpan.FromSeconds(2)); + foreach (var scanner in additional) + { + scanner.Start(); + } - foreach (var operation in operations) + foreach (var operation in operations) + { + if (operation is AssemblyScanner scanner) { - if (operation is AssemblyScanner scanner) scanner.ApplyRegistrations(registry); + scanner.ApplyRegistrations(registry); + } - if (operation is ServiceDescriptor[] descriptors) registry.AddRange(descriptors); + if (operation is ServiceDescriptor[] descriptors) + { + registry.AddRange(descriptors); } } - - return (registry, scanners); } - internal static async Task<(ServiceRegistry, AssemblyScanner[])> Explode(IServiceCollection services) - { - var scanners = new AssemblyScanner[0]; - var registry = new ServiceRegistry(services); - - var registriesEncountered = new List(); + return (registry, scanners); + } - while (registry.HasScanners()) - { - var (registry2, operations) = ParseToOperations(registry, registriesEncountered); + internal static async Task<(ServiceRegistry, AssemblyScanner[])> Explode(IServiceCollection services) + { + var scanners = new AssemblyScanner[0]; + var registry = new ServiceRegistry(services); + + var registriesEncountered = new List(); + + while (registry.HasScanners()) + { + var (registry2, operations) = ParseToOperations(registry, registriesEncountered); - var additional = operations.OfType().ToArray(); + var additional = operations.OfType().ToArray(); - registry = registry2; - scanners = scanners.Concat(additional).ToArray(); + registry = registry2; + scanners = scanners.Concat(additional).ToArray(); - registry.RemoveAll(x => x.ServiceType == typeof(AssemblyScanner)); + registry.RemoveAll(x => x.ServiceType == typeof(AssemblyScanner)); - foreach (var operation in operations) + foreach (var operation in operations) + { + if (operation is AssemblyScanner scanner) { - if (operation is AssemblyScanner scanner) - { - await scanner.TypeFinder; - scanner.ApplyRegistrations(registry); - } + scanner.Start(); + scanner.ApplyRegistrations(registry); + } - if (operation is ServiceDescriptor[] descriptors) registry.AddRange(descriptors); + if (operation is ServiceDescriptor[] descriptors) + { + registry.AddRange(descriptors); } } - - return (registry, scanners); } + return (registry, scanners); + } - private static (ServiceRegistry, List) ParseToOperations(IServiceCollection services, - List registriesEncountered) - { - var scanners = services - .Where(x => x.ServiceType == typeof(AssemblyScanner)) - .ToArray(); - var indexes = scanners - .Select(services.IndexOf) - .ToArray(); + private static (ServiceRegistry, List) ParseToOperations(IServiceCollection services, + List registriesEncountered) + { + var scanners = services + .Where(x => x.ServiceType == typeof(AssemblyScanner)) + .ToArray(); - var operations = new List(); + var indexes = scanners + .Select(services.IndexOf) + .ToArray(); - var initial = indexes[0] > 0 - ? new ServiceRegistry(services.Take(indexes[0])) - : new ServiceRegistry(); + var operations = new List(); - initial.RegistryTypes = registriesEncountered; + var initial = indexes[0] > 0 + ? new ServiceRegistry(services.Take(indexes[0])) + : new ServiceRegistry(); - operations.Add(scanners[0].ImplementationInstance); + initial.RegistryTypes = registriesEncountered; - for (var i = 1; i < indexes.Length; i++) - { - var index = indexes[i]; - var previous = indexes[i - 1]; - - if (previous != index - 1) - { - // they are not sequential, just add a Scan operation - var slice = services.Skip(previous + 1).Take(index - previous - 1).ToArray(); - operations.Add(slice); - } + operations.Add(scanners[0].ImplementationInstance); + for (var i = 1; i < indexes.Length; i++) + { + var index = indexes[i]; + var previous = indexes[i - 1]; - operations.Add(scanners[i].ImplementationInstance); + if (previous != index - 1) + { + // they are not sequential, just add a Scan operation + var slice = services.Skip(previous + 1).Take(index - previous - 1).ToArray(); + operations.Add(slice); } - // Are there more? - if (indexes.Last() != services.Count - 1) operations.Add(services.Skip(indexes.Last() + 1).ToArray()); - return (initial, operations); + operations.Add(scanners[i].ImplementationInstance); } + + // Are there more? + if (indexes.Last() != services.Count - 1) + { + operations.Add(services.Skip(indexes.Last() + 1).ToArray()); + } + + return (initial, operations); } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/ServiceCollectionExtensions.cs b/src/Lamar/Scanning/Conventions/ServiceCollectionExtensions.cs index 798666cc..4de3864d 100644 --- a/src/Lamar/Scanning/Conventions/ServiceCollectionExtensions.cs +++ b/src/Lamar/Scanning/Conventions/ServiceCollectionExtensions.cs @@ -3,84 +3,89 @@ using System.Linq; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +[LamarIgnore] +internal class ConnectedConcretions : List +{ +} + +internal static class ServiceCollectionExtensions { - [LamarIgnore] - internal class ConnectedConcretions : List + public static bool HasScanners(this IEnumerable services) { + return services.Any(x => x.ServiceType == typeof(AssemblyScanner)); } - internal static class ServiceCollectionExtensions + public static ConnectedConcretions ConnectedConcretions(this IServiceCollection services) { - public static bool HasScanners(this IEnumerable services) - { - return services.Any(x => x.ServiceType == typeof(AssemblyScanner)); - } + var concretions = services.FirstOrDefault(x => x.ServiceType == typeof(ConnectedConcretions)) + ?.ImplementationInstance as ConnectedConcretions; - public static ConnectedConcretions ConnectedConcretions(this IServiceCollection services) + if (concretions == null) { - var concretions = services.FirstOrDefault(x => x.ServiceType == typeof(ConnectedConcretions)) - ?.ImplementationInstance as ConnectedConcretions; + concretions = new ConnectedConcretions(); + services.AddSingleton(concretions); + } - if (concretions == null) - { - concretions = new ConnectedConcretions(); - services.AddSingleton(concretions); - } + return concretions; + } - return concretions; - } + /// + /// Add a registration via Lamar's intrinsic Instance type + /// + /// + /// + public static void Add(this IServiceCollection services, Instance instance) + { + services.Add(new ServiceDescriptor(instance.ServiceType, instance)); + } - /// - /// Add a registration via Lamar's intrinsic Instance type - /// - /// - /// - public static void Add(this IServiceCollection services, Instance instance) + public static bool Matches(this ServiceDescriptor descriptor, Type serviceType, Type implementationType) + { + if (descriptor.ServiceType != serviceType) { - services.Add(new ServiceDescriptor(instance.ServiceType, instance)); + return false; } - public static bool Matches(this ServiceDescriptor descriptor, Type serviceType, Type implementationType) + if (descriptor.ImplementationType == implementationType) { - if (descriptor.ServiceType != serviceType) return false; - - if (descriptor.ImplementationType == implementationType) return true; - - if (descriptor.ImplementationInstance is Instance) - return descriptor.ImplementationInstance.As().ImplementationType == implementationType; - - return false; + return true; } - public static Instance AddType(this IServiceCollection services, Type serviceType, Type implementationType, ServiceLifetime lifetime = ServiceLifetime.Transient) + if (descriptor.ImplementationInstance is Instance) { - var hasAlready = services.Any(x => x.Matches(serviceType, implementationType)); - if (!hasAlready) - { - var instance = new ConstructorInstance(serviceType, implementationType, lifetime); + return descriptor.ImplementationInstance.As().ImplementationType == implementationType; + } - services.Add(instance); + return false; + } - return instance; - } + public static Instance AddType(this IServiceCollection services, Type serviceType, Type implementationType, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + var hasAlready = services.Any(x => x.Matches(serviceType, implementationType)); + if (!hasAlready) + { + var instance = new ConstructorInstance(serviceType, implementationType, lifetime); - return null; - } + services.Add(instance); - public static ServiceDescriptor FindDefault(this IServiceCollection services) - { - return services.FindDefault(typeof(T)); + return instance; } - public static ServiceDescriptor FindDefault(this IServiceCollection services, Type serviceType) - { - return services.LastOrDefault(x => x.ServiceType == serviceType); - } + return null; + } + public static ServiceDescriptor FindDefault(this IServiceCollection services) + { + return services.FindDefault(typeof(T)); + } + public static ServiceDescriptor FindDefault(this IServiceCollection services, Type serviceType) + { + return services.LastOrDefault(x => x.ServiceType == serviceType); } } \ No newline at end of file diff --git a/src/Lamar/Scanning/Conventions/TypeExtensions.cs b/src/Lamar/Scanning/Conventions/TypeExtensions.cs index aa1e2517..b5b1724c 100644 --- a/src/Lamar/Scanning/Conventions/TypeExtensions.cs +++ b/src/Lamar/Scanning/Conventions/TypeExtensions.cs @@ -3,56 +3,64 @@ using System.Linq; using System.Reflection; using JasperFx.Core.Reflection; -using JasperFx.CodeGeneration.Util; -namespace Lamar.Scanning.Conventions +namespace Lamar.Scanning.Conventions; + +internal static class TypeExtensions { - internal static class TypeExtensions + public static bool CanBeCreated(this Type type) { - public static bool CanBeCreated(this Type type) - { - return type.IsConcrete() && type.GetConstructors().Any(); - } + return type.IsConcrete() && type.GetConstructors().Any(); + } + + public static Type FindFirstInterfaceThatCloses(this Type implementationType, Type templateType) + { + return implementationType.FindInterfacesThatClose(templateType).FirstOrDefault(); + } + + public static IEnumerable FindInterfacesThatClose(this Type pluggedType, Type templateType) + { + return rawFindInterfacesThatCloses(pluggedType, templateType).Distinct(); + } - public static Type FindFirstInterfaceThatCloses(this Type implementationType, Type templateType) + private static IEnumerable rawFindInterfacesThatCloses(Type TPluggedType, Type templateType) + { + if (!TPluggedType.IsConcrete()) { - return implementationType.FindInterfacesThatClose(templateType).FirstOrDefault(); + yield break; } - public static IEnumerable FindInterfacesThatClose(this Type pluggedType, Type templateType) + if (templateType.GetTypeInfo().IsInterface) { - return rawFindInterfacesThatCloses(pluggedType, templateType).Distinct(); + foreach ( + var interfaceType in + TPluggedType.GetInterfaces() + .Where(type => + type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == templateType)) + yield return interfaceType; } - - private static IEnumerable rawFindInterfacesThatCloses(Type TPluggedType, Type templateType) + else if (TPluggedType.GetTypeInfo().BaseType.GetTypeInfo().IsGenericType && + TPluggedType.GetTypeInfo().BaseType.GetGenericTypeDefinition() == templateType) { - if (!TPluggedType.IsConcrete()) yield break; - - if (templateType.GetTypeInfo().IsInterface) - foreach ( - var interfaceType in - TPluggedType.GetInterfaces() - .Where(type => - type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == templateType)) - yield return interfaceType; - else if (TPluggedType.GetTypeInfo().BaseType.GetTypeInfo().IsGenericType && - TPluggedType.GetTypeInfo().BaseType.GetGenericTypeDefinition() == templateType) - yield return TPluggedType.GetTypeInfo().BaseType; - - if (TPluggedType.GetTypeInfo().BaseType == typeof(object)) yield break; - - foreach (var interfaceType in rawFindInterfacesThatCloses(TPluggedType.GetTypeInfo().BaseType, templateType) - ) yield return interfaceType; + yield return TPluggedType.GetTypeInfo().BaseType; } - public static bool CouldCloseTo(this Type openConcretion, Type closedInterface) + if (TPluggedType.GetTypeInfo().BaseType == typeof(object)) { - var openInterface = closedInterface.GetGenericTypeDefinition(); - var arguments = closedInterface.GetGenericArguments(); - - var concreteArguments = openConcretion.GetGenericArguments(); - return arguments.Length == concreteArguments.Length && openConcretion.CanBeCastTo(openInterface); + yield break; } + + foreach (var interfaceType in rawFindInterfacesThatCloses(TPluggedType.GetTypeInfo().BaseType, templateType) + ) yield return interfaceType; + } + + public static bool CouldCloseTo(this Type openConcretion, Type closedInterface) + { + var openInterface = closedInterface.GetGenericTypeDefinition(); + var arguments = closedInterface.GetGenericArguments(); + + var concreteArguments = openConcretion.GetGenericArguments(); + return arguments.Length == concreteArguments.Length && openConcretion.CanBeCastTo(openInterface); } } \ No newline at end of file diff --git a/src/Lamar/ScopedAttribute.cs b/src/Lamar/ScopedAttribute.cs index ca0aa559..833e2401 100644 --- a/src/Lamar/ScopedAttribute.cs +++ b/src/Lamar/ScopedAttribute.cs @@ -2,18 +2,17 @@ using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +/// +/// Makes Lamar treat a Type as a singleton in the lifecycle scoping +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] +public class ScopedAttribute : LamarAttribute { - /// - /// Makes Lamar treat a Type as a singleton in the lifecycle scoping - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] - public class ScopedAttribute : LamarAttribute + // This method will affect single registrations + public override void Alter(IConfiguredInstance instance) { - // This method will affect single registrations - public override void Alter(IConfiguredInstance instance) - { - instance.Lifetime = ServiceLifetime.Scoped; - } + instance.Lifetime = ServiceLifetime.Scoped; } } \ No newline at end of file diff --git a/src/Lamar/ServiceFamily.cs b/src/Lamar/ServiceFamily.cs index 4939f595..90c27efc 100644 --- a/src/Lamar/ServiceFamily.cs +++ b/src/Lamar/ServiceFamily.cs @@ -4,228 +4,223 @@ using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.IoC.Instances; -using JasperFx.CodeGeneration; using Microsoft.Extensions.DependencyInjection; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +public class ServiceFamily { - public class ServiceFamily + private readonly Dictionary _instances = new(); + + public ServiceFamily(Type serviceType, IDecoratorPolicy[] decoratorPolicies, params Instance[] instances) { - private readonly Dictionary _instances = new Dictionary(); + if (!serviceType.IsOpenGeneric()) + { + // First pass, see if you need to apply any decorators first + instances = applyDecorators(decoratorPolicies, instances).ToArray(); + } + foreach (var instance in instances) + { + instance.IsDefault = false; + instance.IsOnlyOneOfServiceType = false; + } - public Type ServiceType { get; } + if (instances.Any()) + { + instances.Last().IsDefault = true; + } - public ServiceFamily(Type serviceType, IDecoratorPolicy[] decoratorPolicies, params Instance[] instances) + if (instances.Length == 1) { - if (!serviceType.IsOpenGeneric()) - { - // First pass, see if you need to apply any decorators first - instances = applyDecorators(decoratorPolicies, instances).ToArray(); - } - - foreach (var instance in instances) - { - instance.IsDefault = false; - instance.IsOnlyOneOfServiceType = false; - } + instances[0].IsOnlyOneOfServiceType = true; + } - if (instances.Any()) - { - instances.Last().IsDefault = true; - } + ServiceType = serviceType; - if (instances.Length == 1) - { - instances[0].IsOnlyOneOfServiceType = true; - } + Default = instances.LastOrDefault(); - ServiceType = serviceType; - Default = instances.LastOrDefault(); + makeNamesUnique(instances); + foreach (var instance in instances) _instances.Add(instance.Name, instance); - makeNamesUnique(instances); + All = instances; - foreach (var instance in instances) - { - _instances.Add(instance.Name, instance); - } + FullNameInCode = serviceType.FullNameInCode(); + } - All = instances; - FullNameInCode = serviceType.FullNameInCode(); - } + public Type ServiceType { get; } - private IEnumerable allDecoratorPolicies(IDecoratorPolicy[] decoratorPolicies) - { - foreach (var decoratorPolicy in decoratorPolicies) - { - yield return decoratorPolicy; - } - - yield return MaybeIntercepted.Instance; - } + public string FullNameInCode { get; } - private IEnumerable applyDecorators(IDecoratorPolicy[] decoratorPolicies, Instance[] instances) - { - foreach (var instance in instances) - { - Instance current = instance; + // Has to be in order here + public Instance[] All { get; private set; } - var originalName = instance.Name; - var originalLifetime = instance.Lifetime; + public Instance Default { get; private set; } + public IReadOnlyDictionary Instances => _instances; - foreach (var decoratorPolicy in allDecoratorPolicies(decoratorPolicies)) - { - if (decoratorPolicy.TryWrap(current, out var wrapped)) - { - wrapped.Lifetime = originalLifetime; - wrapped.Name = originalName; - - current.Lifetime = ServiceLifetime.Transient; - - current = wrapped; - } - } + // Used internally to explain why the service type cannot be resolved + public string CannotBeResolvedMessage { get; set; } - yield return current; - } - } - - public string FullNameInCode { get; } + private IEnumerable allDecoratorPolicies(IDecoratorPolicy[] decoratorPolicies) + { + foreach (var decoratorPolicy in decoratorPolicies) yield return decoratorPolicy; + yield return MaybeIntercepted.Instance; + } - public AppendState Append(ObjectInstance instance, IDecoratorPolicy[] decoration) + private IEnumerable applyDecorators(IDecoratorPolicy[] decoratorPolicies, Instance[] instances) + { + foreach (var instance in instances) { - return Append(new Instance[]{instance}, decoration); - } + var current = instance; - public AppendState Append(IEnumerable services, IDecoratorPolicy[] decoration) - { - var instances = services.Select(Instance.For).ToArray(); - - return Append(instances, decoration); - } + var originalName = instance.Name; + var originalLifetime = instance.Lifetime; - public AppendState Append(Instance[] instances, IDecoratorPolicy[] decoration) - { - instances = applyDecorators(decoration, instances).ToArray(); - - var currentDefault = Default; - - foreach (var instance in instances) - { - instance.IsDefault = false; - } - if (instances.Any()) + foreach (var decoratorPolicy in allDecoratorPolicies(decoratorPolicies)) { - instances.Last().IsDefault = true; + if (decoratorPolicy.TryWrap(current, out var wrapped)) + { + wrapped.Lifetime = originalLifetime; + wrapped.Name = originalName; + + current.Lifetime = ServiceLifetime.Transient; + + current = wrapped; + } } - Default = instances.LastOrDefault(); + yield return current; + } + } - var all = All.Concat(instances).ToArray(); - makeNamesUnique(all); + public AppendState Append(ObjectInstance instance, IDecoratorPolicy[] decoration) + { + return Append(new Instance[] { instance }, decoration); + } - _instances.Clear(); - - foreach (var instance in all) - { - while (_instances.ContainsKey(instance.Name)) - { - instance.Name += "_2"; - } - - _instances.Add(instance.Name, instance); - } + public AppendState Append(IEnumerable services, IDecoratorPolicy[] decoration) + { + var instances = services.Select(Instance.For).ToArray(); - foreach (var instance in all) - { - instance.IsOnlyOneOfServiceType = false; - } + return Append(instances, decoration); + } - if (all.Length == 1) - { - all[0].IsOnlyOneOfServiceType = true; - } + public AppendState Append(Instance[] instances, IDecoratorPolicy[] decoration) + { + instances = applyDecorators(decoration, instances).ToArray(); - All = all; + var currentDefault = Default; - if (currentDefault == null && Default != null) return AppendState.NewDefault; + foreach (var instance in instances) instance.IsDefault = false; - return currentDefault == Default ? AppendState.SameDefault : AppendState.NewDefault; + if (instances.Any()) + { + instances.Last().IsDefault = true; } - public override string ToString() + Default = instances.LastOrDefault(); + + + var all = All.Concat(instances).ToArray(); + makeNamesUnique(all); + + _instances.Clear(); + + foreach (var instance in all) { - return $"{nameof(ServiceType)}: {ServiceType.FullNameInCode()}"; + while (_instances.ContainsKey(instance.Name)) + { + instance.Name += "_2"; + } + + _instances.Add(instance.Name, instance); } - // Has to be in order here - public Instance[] All { get; private set; } + foreach (var instance in all) instance.IsOnlyOneOfServiceType = false; - public Instance InstanceFor(string name) + if (all.Length == 1) { - return Instances.ContainsKey(name) ? Instances[name] : _instances.Values.ToArray().FirstOrDefault(x => x.Name == name); + all[0].IsOnlyOneOfServiceType = true; } - private void makeNamesUnique(IEnumerable instances) + All = all; + + if (currentDefault == null && Default != null) { - instances - .GroupBy(x => x.Name) - .Select(x => x.ToArray()) - .Where(x => x.Length > 1) - .Each(array => - { - for (int i = 0; i < array.Length; i++) - { - array[i].Name += (i + 1).ToString(); - } - }); + return AppendState.NewDefault; } - public Instance Default { get; private set; } - - public IReadOnlyDictionary Instances => _instances; - - // Used internally to explain why the service type cannot be resolved - public string CannotBeResolvedMessage { get; set; } + return currentDefault == Default ? AppendState.SameDefault : AppendState.NewDefault; + } + public override string ToString() + { + return $"{nameof(ServiceType)}: {ServiceType.FullNameInCode()}"; + } - /// - /// If the ServiceType is an open generic type, this method will create a - /// closed type copy of this PluginFamily - /// - /// - /// - /// - /// - public ServiceFamily CreateTemplatedClone(Type serviceType, IDecoratorPolicy[] decoration, Type[] templateTypes) - { - if (!ServiceType.IsGenericType) throw new InvalidOperationException($"{ServiceType.FullNameInCode()} is not an open generic type"); + public Instance InstanceFor(string name) + { + return Instances.ContainsKey(name) + ? Instances[name] + : _instances.Values.ToArray().FirstOrDefault(x => x.Name == name); + } - var instances = _instances.Values.ToArray().Select(x => { - var clone = x.CloseType(serviceType, templateTypes); - if (clone == null) return null; + private void makeNamesUnique(IEnumerable instances) + { + instances + .GroupBy(x => x.Name) + .Select(x => x.ToArray()) + .Where(x => x.Length > 1) + .Each(array => + { + for (var i = 0; i < array.Length; i++) + { + array[i].Name += (i + 1).ToString(); + } + }); + } - clone.Name = x.Name; - return clone; - }).Where(x => x != null).ToArray(); - return new ServiceFamily(serviceType, decoration, instances); + /// + /// If the ServiceType is an open generic type, this method will create a + /// closed type copy of this PluginFamily + /// + /// + /// + /// + /// + public ServiceFamily CreateTemplatedClone(Type serviceType, IDecoratorPolicy[] decoration, Type[] templateTypes) + { + if (!ServiceType.IsGenericType) + { + throw new InvalidOperationException($"{ServiceType.FullNameInCode()} is not an open generic type"); } + var instances = _instances.Values.ToArray().Select(x => + { + var clone = x.CloseType(serviceType, templateTypes); + if (clone == null) + { + return null; + } - } + clone.Name = x.Name; + return clone; + }).Where(x => x != null).ToArray(); - public enum AppendState - { - NewDefault, - SameDefault + return new ServiceFamily(serviceType, decoration, instances); } } + +public enum AppendState +{ + NewDefault, + SameDefault +} \ No newline at end of file diff --git a/src/Lamar/ServiceFamilyConfiguration.cs b/src/Lamar/ServiceFamilyConfiguration.cs index 4cc926d8..ff7c2792 100644 --- a/src/Lamar/ServiceFamilyConfiguration.cs +++ b/src/Lamar/ServiceFamilyConfiguration.cs @@ -4,22 +4,25 @@ using Lamar.Diagnostics; using Lamar.IoC; -namespace Lamar +namespace Lamar; + +internal class ServiceFamilyConfiguration : IServiceFamilyConfiguration { - internal class ServiceFamilyConfiguration : IServiceFamilyConfiguration + private readonly ServiceFamily _family; + private readonly Scope _scope; + + public ServiceFamilyConfiguration(ServiceFamily family, Scope scope) { - private readonly ServiceFamily _family; - private readonly Scope _scope; + _family = family; + _scope = scope; + } - public ServiceFamilyConfiguration(ServiceFamily family, Scope scope) - { - _family = family; - _scope = scope; - } + public Type ServiceType => _family.ServiceType; + public InstanceRef Default => _family.Default == null ? null : new InstanceRef(_family.Default, _scope); + public IEnumerable Instances => _family.All.Select(x => new InstanceRef(x, _scope)); - public Type ServiceType => _family.ServiceType; - public InstanceRef Default => _family.Default == null ? null : new InstanceRef(_family.Default, _scope); - public IEnumerable Instances => _family.All.Select(x => new InstanceRef(x, _scope)); - public bool HasImplementations() => _family.All.Any(); + public bool HasImplementations() + { + return _family.All.Any(); } } \ No newline at end of file diff --git a/src/Lamar/ServiceGraph.cs b/src/Lamar/ServiceGraph.cs index 9b143860..01222e3f 100644 --- a/src/Lamar/ServiceGraph.cs +++ b/src/Lamar/ServiceGraph.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; +using JasperFx.CodeGeneration; using JasperFx.Core; using JasperFx.Core.Reflection; using Lamar.IoC; @@ -14,564 +14,558 @@ using Lamar.IoC.Setters; using Lamar.Scanning.Conventions; using Lamar.Util; -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Util; using Microsoft.Extensions.DependencyInjection; -namespace Lamar -{ - public class ServiceGraph : IDisposable, IAsyncDisposable - { - private readonly object _familyLock = new object(); - - private ImHashMap _families = ImHashMap.Empty; - private ImHashMap> _byType = ImHashMap>.Empty; - - - public static async Task BuildAsync(IServiceCollection services, Scope rootScope) - { - var (registry, scanners) = await ScanningExploder.Explode(services); - - return new ServiceGraph(registry, rootScope, scanners); - } - - - private ServiceGraph(IServiceCollection services, Scope rootScope, AssemblyScanner[] scanners) - { - _services = services as ServiceRegistry ?? new ServiceRegistry(services); - Scanners = scanners; - RootScope = rootScope; - organize(_services); - } - - public ServiceGraph(IServiceCollection services, Scope rootScope) - { - var (registry, scanners) = ScanningExploder.ExplodeSynchronously(services); +namespace Lamar; - Scanners = scanners; - - _services = registry; +public class ServiceGraph : IDisposable, IAsyncDisposable +{ + private readonly Stack _chain = new(); + private readonly object _familyLock = new(); - RootScope = rootScope; + private readonly IList _lookingFor = new List(); + private readonly ServiceRegistry _services; + private Assembly[] _allAssemblies; + private ImHashMap> _byType = ImHashMap>.Empty; - organize(_services); - } + private ImHashMap _families = ImHashMap.Empty; - public Scope RootScope { get; } + private bool _inPlanning; - private void organize(ServiceRegistry services) - { - DecoratorPolicies = services.FindAndRemovePolicies(); - - FamilyPolicies = services.FindAndRemovePolicies() - .Concat(new IFamilyPolicy[] - { - new EnumerablePolicy(), - new FuncOrLazyPolicy(), - new CloseGenericFamilyPolicy(), - new ConcreteFamilyPolicy(), - new EmptyFamilyPolicy() - }) - .ToArray(); - - - setterPolicies = services.FindAndRemovePolicies(); - InstancePolicies = services.FindAndRemovePolicies(); - - var policies = services.FindAndRemovePolicies(); - foreach (var policy in policies) - { - policy.Apply(services); - } + private ServiceGraph(IServiceCollection services, Scope rootScope, AssemblyScanner[] scanners) + { + _services = services as ServiceRegistry ?? new ServiceRegistry(services); + Scanners = scanners; + RootScope = rootScope; + organize(_services); + } - services.Add(new ScopeInstance()); - services.Add(new ScopeInstance()); - services.Add(new ScopeInstance()); - - services.Add(new ScopeInstance());; - services.Add(new RootScopeInstance());; + public ServiceGraph(IServiceCollection services, Scope rootScope) + { + var (registry, scanners) = ScanningExploder.ExplodeSynchronously(services); - } + Scanners = scanners; - private ISetterPolicy[] setterPolicies { get; set; } + _services = registry; - internal bool ShouldBeSet(PropertyInfo property) - { - return property.HasAttribute() || setterPolicies.Any(x => x.Matches(property)); - } + RootScope = rootScope; - public IDecoratorPolicy[] DecoratorPolicies { get; private set; } = new IDecoratorPolicy[0]; + organize(_services); + } - internal void Inject(Type serviceType, object @object) - { - _byType = _byType.AddOrUpdate(serviceType, s => @object); - } + public Scope RootScope { get; } - public IInstancePolicy[] InstancePolicies { get; set; } + private ISetterPolicy[] setterPolicies { get; set; } - public IFamilyPolicy[] FamilyPolicies { get; private set; } + public IDecoratorPolicy[] DecoratorPolicies { get; private set; } = new IDecoratorPolicy[0]; + public IInstancePolicy[] InstancePolicies { get; set; } - public void Initialize() - { - organizeIntoFamilies(_services); - buildOutMissingResolvers(); - rebuildReferencedAssemblyArray(); - } + public IFamilyPolicy[] FamilyPolicies { get; private set; } + public IServiceCollection Services => _services; - private void rebuildReferencedAssemblyArray() - { - _allAssemblies = AllInstances().SelectMany(x => x.ReferencedAssemblies()) - .Distinct().ToArray(); - } + public IReadOnlyDictionary Families => _families.ToDictionary(); + internal AssemblyScanner[] Scanners { get; private set; } = new AssemblyScanner[0]; - private void buildOutMissingResolvers() + public async ValueTask DisposeAsync() + { + foreach (var instance in AllInstances().OfType()) { - if (_inPlanning) return; - - _inPlanning = true; - - try + if (instance.Service is IAsyncDisposable a) { - planResolutionStrategies(); + try + { + await a.DisposeAsync(); + } + catch (Exception) + { + } } - finally + else if (instance.Service is IDisposable d) { - _inPlanning = false; + d.SafeDispose(); } } + } - - internal GeneratedAssembly ToGeneratedAssembly(string @namespace = null) - { - // TODO -- will need to get at the GenerationRules from somewhere - var generatedAssembly = new GeneratedAssembly(new GenerationRules(@namespace ?? "Lamar.Generated")); - - generatedAssembly.Rules.Assemblies.Fill(_allAssemblies); - - return generatedAssembly; - } - - private bool _inPlanning = false; - - private void resetInstancePlanning() + public void Dispose() + { + foreach (var instance in AllInstances().OfType()) { - foreach (var instance in AllInstances()) + if (instance.Service is IDisposable d) { - instance.Reset(); + d.SafeDispose(); } - } - - private void planResolutionStrategies() - { - while (AllInstances().Where(x => !x.ServiceType.IsOpenGeneric()).Any(x => !x.HasPlanned)) + else if (instance.Service is IAsyncDisposable a) { - foreach (var instance in AllInstances().Where(x => !x.HasPlanned).ToArray()) + try { - instance.CreatePlan(this); + a.DisposeAsync().GetAwaiter().GetResult(); } - } - } - - internal Instance FindInstance(ParameterInfo parameter) - { - if (parameter.HasAttribute()) - { - var att = parameter.GetAttribute(); - if (att.TypeName.IsNotEmpty()) + catch (Exception) { - var family = _families.Enumerate().ToArray().FirstOrDefault(x => x.Value.FullNameInCode == att.TypeName); - return family?.Value.InstanceFor(att.Name); } - - return FindInstance(parameter.ParameterType, att.Name); } - - return FindDefault(parameter.ParameterType); } + } - private void organizeIntoFamilies(IServiceCollection services) - { - var serviceFamilies = services - .Where(x => !x.ServiceType.HasAttribute()) - .GroupBy(x => x.ServiceType) - .Select(group => buildFamilyForInstanceGroup(services, group)); + public static async Task BuildAsync(IServiceCollection services, Scope rootScope) + { + var (registry, scanners) = await ScanningExploder.Explode(services); - foreach (var family in serviceFamilies) - { - _families = _families.AddOrUpdate(family.ServiceType, family); - } - } + return new ServiceGraph(registry, rootScope, scanners); + } - private ServiceFamily buildFamilyForInstanceGroup(IServiceCollection services, IGrouping @group) - { - if (@group.Key.IsGenericType && !@group.Key.IsOpenGeneric()) + private void organize(ServiceRegistry services) + { + DecoratorPolicies = services.FindAndRemovePolicies(); + + FamilyPolicies = services.FindAndRemovePolicies() + .Concat(new IFamilyPolicy[] { - return buildClosedGenericType(@group.Key, services); - } + new EnumerablePolicy(), + new FuncOrLazyPolicy(), + new CloseGenericFamilyPolicy(), + new ConcreteFamilyPolicy(), + new EmptyFamilyPolicy() + }) + .ToArray(); - var instances = @group - .Select(Instance.For) - .ToArray(); - - return new ServiceFamily(@group.Key, DecoratorPolicies, instances); - } - private ServiceFamily buildClosedGenericType(Type serviceType, IServiceCollection services) - { - var closed = services.Where(x => x.ServiceType == serviceType && !x.ImplementationType.IsOpenGeneric()).Select(Instance.For); + setterPolicies = services.FindAndRemovePolicies(); + InstancePolicies = services.FindAndRemovePolicies(); - var templated = services - .Where(x => x.ServiceType.IsOpenGeneric() && serviceType.Closes(x.ServiceType)) - .Select(Instance.For) - .Select(instance => - { - var arguments = serviceType.GetGenericArguments(); + var policies = services.FindAndRemovePolicies(); + foreach (var policy in policies) policy.Apply(services); - try - { - return instance.CloseType(serviceType, arguments); - } - catch (Exception) - { - return null; - } - }) - .Where(x => x != null); + services.Add(new ScopeInstance()); + services.Add(new ScopeInstance()); + services.Add(new ScopeInstance()); + + services.Add(new ScopeInstance()); + ; + services.Add(new RootScopeInstance()); + ; + } + internal bool ShouldBeSet(PropertyInfo property) + { + return property.HasAttribute() || setterPolicies.Any(x => x.Matches(property)); + } - var instances = templated.Concat(closed).ToArray(); + internal void Inject(Type serviceType, object @object) + { + _byType = _byType.AddOrUpdate(serviceType, s => @object); + } - return new ServiceFamily(serviceType, DecoratorPolicies, instances); - } - public IServiceCollection Services => _services; + public void Initialize() + { + organizeIntoFamilies(_services); + buildOutMissingResolvers(); + rebuildReferencedAssemblyArray(); + } + - public IEnumerable AllInstances() + private void rebuildReferencedAssemblyArray() + { + _allAssemblies = AllInstances().SelectMany(x => x.ReferencedAssemblies()) + .Distinct().ToArray(); + } + + + private void buildOutMissingResolvers() + { + if (_inPlanning) { - return _families.Enumerate().Select(x => x.Value).ToArray().SelectMany(x => x.All).ToArray(); + return; } - public IReadOnlyDictionary Families => _families.ToDictionary(); + _inPlanning = true; - public bool HasFamily(Type serviceType) + try { - return _families.Contains(serviceType); + planResolutionStrategies(); } + finally + { + _inPlanning = false; + } + } + - public Instance FindInstance(Type serviceType, string name) + internal GeneratedAssembly ToGeneratedAssembly(string @namespace = null) + { + // TODO -- will need to get at the GenerationRules from somewhere + var generatedAssembly = new GeneratedAssembly(new GenerationRules(@namespace ?? "Lamar.Generated")); + + generatedAssembly.Rules.Assemblies.Fill(_allAssemblies); + + return generatedAssembly; + } + + private void resetInstancePlanning() + { + foreach (var instance in AllInstances()) instance.Reset(); + } + + private void planResolutionStrategies() + { + while (AllInstances().Where(x => !x.ServiceType.IsOpenGeneric()).Any(x => !x.HasPlanned)) { - return ResolveFamily(serviceType).InstanceFor(name); + foreach (var instance in AllInstances().Where(x => !x.HasPlanned).ToArray()) instance.CreatePlan(this); } + } - public ServiceFamily ResolveFamily(Type serviceType) + internal Instance FindInstance(ParameterInfo parameter) + { + if (parameter.HasAttribute()) { - if (_families.TryFind(serviceType, out var family)) + var att = parameter.GetAttribute(); + if (att.TypeName.IsNotEmpty()) { - return family; + var family = _families.Enumerate().ToArray() + .FirstOrDefault(x => x.Value.FullNameInCode == att.TypeName); + return family?.Value.InstanceFor(att.Name); } - - lock (_familyLock) - { - if (_families.TryFind(serviceType, out family)) - { - return family; - } - return addMissingFamily(serviceType); - } + return FindInstance(parameter.ParameterType, att.Name); } - private ServiceFamily addMissingFamily(Type serviceType) - { - var family = TryToCreateMissingFamily(serviceType); - - _families = _families.AddOrUpdate(serviceType, family); + return FindDefault(parameter.ParameterType); + } - if (!_inPlanning) - { - buildOutMissingResolvers(); + private void organizeIntoFamilies(IServiceCollection services) + { + var serviceFamilies = services + .Where(x => !x.ServiceType.HasAttribute()) + .GroupBy(x => x.ServiceType) + .Select(group => buildFamilyForInstanceGroup(services, group)); - if (family != null) - { - rebuildReferencedAssemblyArray(); - } - } + foreach (var family in serviceFamilies) _families = _families.AddOrUpdate(family.ServiceType, family); + } - return family; + private ServiceFamily buildFamilyForInstanceGroup(IServiceCollection services, + IGrouping group) + { + if (group.Key.IsGenericType && !group.Key.IsOpenGeneric()) + { + return buildClosedGenericType(group.Key, services); } - public Func FindResolver(Type serviceType) - { - if (_byType.TryFind(serviceType, out Func resolver)) - { - return resolver; - } + var instances = group + .Select(Instance.For) + .ToArray(); - lock (_familyLock) - { - if (_byType.TryFind(serviceType, out resolver)) - { - return resolver; - } + return new ServiceFamily(group.Key, DecoratorPolicies, instances); + } - var family = ResolveFamily(serviceType); + private ServiceFamily buildClosedGenericType(Type serviceType, IServiceCollection services) + { + var closed = services.Where(x => x.ServiceType == serviceType && !x.ImplementationType.IsOpenGeneric()) + .Select(Instance.For); - var instance = family.Default; - if (instance == null) - { - resolver = null; - } - else if (instance.Lifetime == ServiceLifetime.Singleton) - { - var inner = instance.ToResolver(RootScope); - resolver = s => - { - var value = inner(s); - Inject(serviceType, value); + var templated = services + .Where(x => x.ServiceType.IsOpenGeneric() && serviceType.Closes(x.ServiceType)) + .Select(Instance.For) + .Select(instance => + { + var arguments = serviceType.GetGenericArguments(); - return value; - }; + try + { + return instance.CloseType(serviceType, arguments); } - else + catch (Exception) { - resolver = instance.ToResolver(RootScope); + return null; } + }) + .Where(x => x != null); - _byType = _byType.AddOrUpdate(serviceType, resolver); - return resolver; - } - } + var instances = templated.Concat(closed).ToArray(); - public Instance FindDefault(Type serviceType) - { - if (serviceType.ShouldIgnore()) return null; + return new ServiceFamily(serviceType, DecoratorPolicies, instances); + } - return ResolveFamily(serviceType)?.Default; - } + public IEnumerable AllInstances() + { + return _families.Enumerate().Select(x => x.Value).ToArray().SelectMany(x => x.All).ToArray(); + } + + public bool HasFamily(Type serviceType) + { + return _families.Contains(serviceType); + } + + public Instance FindInstance(Type serviceType, string name) + { + return ResolveFamily(serviceType).InstanceFor(name); + } - public Instance[] FindAll(Type serviceType) + public ServiceFamily ResolveFamily(Type serviceType) + { + if (_families.TryFind(serviceType, out var family)) { - return ResolveFamily(serviceType)?.All ?? new Instance[0]; + return family; } - public bool CouldBuild(Type concreteType, out string message) + lock (_familyLock) { - var constructorInstance = new ConstructorInstance(concreteType, concreteType, ServiceLifetime.Transient); - foreach (var policy in InstancePolicies) + if (_families.TryFind(serviceType, out family)) { - policy.Apply(constructorInstance); + return family; } - - var ctor = constructorInstance.DetermineConstructor(this, out message); - - - return ctor != null && message.IsEmpty(); + + return addMissingFamily(serviceType); } + } + + private ServiceFamily addMissingFamily(Type serviceType) + { + var family = TryToCreateMissingFamily(serviceType); + + _families = _families.AddOrUpdate(serviceType, family); - public void Dispose() + if (!_inPlanning) { - foreach (var instance in AllInstances().OfType()) + buildOutMissingResolvers(); + + if (family != null) { - if (instance.Service is IDisposable d) - { - d.SafeDispose(); - } - else if (instance.Service is IAsyncDisposable a) - { - try - { - a.DisposeAsync().GetAwaiter().GetResult(); - } - catch (Exception) - { - - } - } + rebuildReferencedAssemblyArray(); } } - public async ValueTask DisposeAsync() + return family; + } + + public Func FindResolver(Type serviceType) + { + if (_byType.TryFind(serviceType, out var resolver)) { - foreach (var instance in AllInstances().OfType()) + return resolver; + } + + lock (_familyLock) + { + if (_byType.TryFind(serviceType, out resolver)) { - if (instance.Service is IAsyncDisposable a) - { - try - { - await a.DisposeAsync(); - } - catch (Exception) - { - - } - } - else if (instance.Service is IDisposable d) - { - d.SafeDispose(); - } - - + return resolver; } - } - private readonly Stack _chain = new Stack(); - private Assembly[] _allAssemblies; - private readonly ServiceRegistry _services; + var family = ResolveFamily(serviceType); - internal AssemblyScanner[] Scanners { get; private set; } = new AssemblyScanner[0]; + var instance = family.Default; + if (instance == null) + { + resolver = null; + } + else if (instance.Lifetime == ServiceLifetime.Singleton) + { + var inner = instance.ToResolver(RootScope); + resolver = s => + { + var value = inner(s); + Inject(serviceType, value); - internal void StartingToPlan(Instance instance) - { - if (_chain.Contains(instance)) + return value; + }; + } + else { - throw new InvalidOperationException("Bi-directional dependencies detected:" + Environment.NewLine + _chain.Select(x => x.ToString()).Join(Environment.NewLine)); + resolver = instance.ToResolver(RootScope); } - _chain.Push(instance); + _byType = _byType.AddOrUpdate(serviceType, resolver); + + return resolver; } + } - internal void FinishedPlanning() + public Instance FindDefault(Type serviceType) + { + if (serviceType.ShouldIgnore()) { - _chain.Pop(); + return null; } - public static ServiceGraph Empty() + return ResolveFamily(serviceType)?.Default; + } + + public Instance[] FindAll(Type serviceType) + { + return ResolveFamily(serviceType)?.All ?? new Instance[0]; + } + + public bool CouldBuild(Type concreteType, out string message) + { + var constructorInstance = new ConstructorInstance(concreteType, concreteType, ServiceLifetime.Transient); + foreach (var policy in InstancePolicies) policy.Apply(constructorInstance); + + var ctor = constructorInstance.DetermineConstructor(this, out message); + + + return ctor != null && message.IsEmpty(); + } + + internal void StartingToPlan(Instance instance) + { + if (_chain.Contains(instance)) { - return Scope.Empty().ServiceGraph; + throw new InvalidOperationException("Bi-directional dependencies detected:" + Environment.NewLine + + _chain.Select(x => x.ToString()).Join(Environment.NewLine)); } - public static ServiceGraph For(Action configure) - { - var registry = new ServiceRegistry(); - configure(registry); + _chain.Push(instance); + } - return new Scope(registry).ServiceGraph; - } + internal void FinishedPlanning() + { + _chain.Pop(); + } - private readonly IList _lookingFor = new List(); + public static ServiceGraph Empty() + { + return Scope.Empty().ServiceGraph; + } - - public ServiceFamily TryToCreateMissingFamily(Type serviceType) - { - if (_lookingFor.Contains(serviceType)) - { - throw new InvalidOperationException($"Detected some kind of bi-directional dependency while trying to discover and plan a missing service registration. Examining types: {_lookingFor.Select(x => x.FullNameInCode()).Join(", ")}"); - } - - _lookingFor.Add(serviceType); - - if (serviceType.ShouldIgnore()) return new ServiceFamily(serviceType, DecoratorPolicies); + public static ServiceGraph For(Action configure) + { + var registry = new ServiceRegistry(); + configure(registry); - var found = FamilyPolicies.FirstValue(x => x.Build(serviceType, this)); + return new Scope(registry).ServiceGraph; + } - _lookingFor.Remove(serviceType); - return found; + public ServiceFamily TryToCreateMissingFamily(Type serviceType) + { + if (_lookingFor.Contains(serviceType)) + { + throw new InvalidOperationException( + $"Detected some kind of bi-directional dependency while trying to discover and plan a missing service registration. Examining types: {_lookingFor.Select(x => x.FullNameInCode()).Join(", ")}"); } - - internal ServiceFamily TryToCreateMissingFamilyWithNetCoreRules(Type serviceType) + + _lookingFor.Add(serviceType); + + if (serviceType.ShouldIgnore()) { - if (_lookingFor.Contains(serviceType)) - { - throw new InvalidOperationException($"Detected some kind of bi-directional dependency while trying to discover and plan a missing service registration. Examining types: {_lookingFor.Select(x => x.FullNameInCode()).Join(", ")}"); - } - - _lookingFor.Add(serviceType); - - if (serviceType.ShouldIgnore()) return new ServiceFamily(serviceType, DecoratorPolicies); + return new ServiceFamily(serviceType, DecoratorPolicies); + } - var found = FamilyPolicies.Where(x => x is not ConcreteFamilyPolicy).FirstValue(x => x.Build(serviceType, this)); + var found = FamilyPolicies.FirstValue(x => x.Build(serviceType, this)); - _lookingFor.Remove(serviceType); + _lookingFor.Remove(serviceType); - return found; - } + return found; + } - internal void ClearPlanning() + internal ServiceFamily TryToCreateMissingFamilyWithNetCoreRules(Type serviceType) + { + if (_lookingFor.Contains(serviceType)) { - _chain.Clear(); + throw new InvalidOperationException( + $"Detected some kind of bi-directional dependency while trying to discover and plan a missing service registration. Examining types: {_lookingFor.Select(x => x.FullNameInCode()).Join(", ")}"); } - public bool CouldResolve(Type type) + _lookingFor.Add(serviceType); + + if (serviceType.ShouldIgnore()) { - return FindDefault(type) != null; + return new ServiceFamily(serviceType, DecoratorPolicies); } + var found = FamilyPolicies.Where(x => x is not ConcreteFamilyPolicy) + .FirstValue(x => x.Build(serviceType, this)); + + _lookingFor.Remove(serviceType); + + return found; + } + + internal void ClearPlanning() + { + _chain.Clear(); + } + + public bool CouldResolve(Type type) + { + return FindDefault(type) != null; + } + - public void AppendServices(IServiceCollection services) + public void AppendServices(IServiceCollection services) + { + lock (_familyLock) { - lock (_familyLock) - { - var (registry, scanners) = ScanningExploder.ExplodeSynchronously(services); + var (registry, scanners) = ScanningExploder.ExplodeSynchronously(services); - Scanners = Scanners.Union(scanners).ToArray(); + Scanners = Scanners.Union(scanners).ToArray(); - var groups = registry - .Where(x => !x.ServiceType.HasAttribute()) - .GroupBy(x => x.ServiceType); + var groups = registry + .Where(x => !x.ServiceType.HasAttribute()) + .GroupBy(x => x.ServiceType); - foreach (var group in groups) + foreach (var group in groups) + { + if (_families.TryFind(group.Key, out var family)) { - if (_families.TryFind(group.Key, out var family)) + if (family.Append(group, DecoratorPolicies) == AppendState.NewDefault) { - if (family.Append(@group, DecoratorPolicies) == AppendState.NewDefault) - { - _byType = _byType.Remove(group.Key); - } - } - else - { - family = buildFamilyForInstanceGroup(services, @group); - _families = _families.AddOrUpdate(group.Key, family); + _byType = _byType.Remove(group.Key); } } + else + { + family = buildFamilyForInstanceGroup(services, group); + _families = _families.AddOrUpdate(group.Key, family); + } + } - resetInstancePlanning(); + resetInstancePlanning(); - buildOutMissingResolvers(); - - rebuildReferencedAssemblyArray(); - } + buildOutMissingResolvers(); + rebuildReferencedAssemblyArray(); } + } - public bool CanBeServiceByNetCoreRules(Type serviceType) + public bool CanBeServiceByNetCoreRules(Type serviceType) + { + if (_families.TryFind(serviceType, out var family)) { - if (_families.TryFind(serviceType, out var family)) + return family.Default != null; + } + + lock (_familyLock) + { + if (_families.TryFind(serviceType, out family)) { return family.Default != null; } - lock (_familyLock) + family = TryToCreateMissingFamilyWithNetCoreRules(serviceType); + _families = _families.AddOrUpdate(serviceType, family); + + if (!_inPlanning) { - if (_families.TryFind(serviceType, out family)) - { - return family.Default != null; - } - - family = TryToCreateMissingFamilyWithNetCoreRules(serviceType); - _families = _families.AddOrUpdate(serviceType, family); + buildOutMissingResolvers(); - if (!_inPlanning) + if (family != null) { - buildOutMissingResolvers(); - - if (family != null) - { - rebuildReferencedAssemblyArray(); - } + rebuildReferencedAssemblyArray(); } } - - return family.Default != null; } + + return family.Default != null; } -} +} \ No newline at end of file diff --git a/src/Lamar/ServiceRegistry.InverseInstanceExpression.cs b/src/Lamar/ServiceRegistry.InverseInstanceExpression.cs index 4304508e..cb0b8b58 100644 --- a/src/Lamar/ServiceRegistry.InverseInstanceExpression.cs +++ b/src/Lamar/ServiceRegistry.InverseInstanceExpression.cs @@ -1,152 +1,152 @@ -using Lamar.IoC.Instances; +using System; +using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -using System; -namespace Lamar +namespace Lamar; + +public partial class ServiceRegistry { - public partial class ServiceRegistry + public class ProvidedInstanceInverseInstanceExpression : BaseInverseInstanceExpression + where TImpl : class { - public class ProvidedInstanceInverseInstanceExpression : BaseInverseInstanceExpression - where TImpl : class + private readonly TImpl _instance; + + public ProvidedInstanceInverseInstanceExpression(ServiceRegistry parent, TImpl instance) + : base(parent) { - public ProvidedInstanceInverseInstanceExpression(ServiceRegistry parent, TImpl instance) - : base(parent) - { - _instance = instance; - } + _instance = instance; + } - private readonly TImpl _instance; + public override ScopedInverseInstanceExpression Named(string name) + { + return new ScopedInverseInstanceExpression(Parent, _instance, name); + } - public override ScopedInverseInstanceExpression Named(string name) - { - return new ScopedInverseInstanceExpression(Parent, _instance, name); - } + public override ScopedInverseInstanceExpression Singleton() + { + return new ScopedInverseInstanceExpression(Parent, _instance); + } + } - public override ScopedInverseInstanceExpression Singleton() - { - return new ScopedInverseInstanceExpression(Parent, _instance); - } + public class InverseInstanceExpression : BaseInverseInstanceExpression + where TImpl : class + { + public InverseInstanceExpression(ServiceRegistry parent) + : base(parent) + { } - public class InverseInstanceExpression : BaseInverseInstanceExpression - where TImpl : class + public ScopedInverseInstanceExpression Transient() { - public InverseInstanceExpression(ServiceRegistry parent) - : base(parent) - { - } + return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Transient); + } - public ScopedInverseInstanceExpression Transient() - { - return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Transient); - } + public ScopedInverseInstanceExpression Scoped() + { + return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Scoped); + } + } - public ScopedInverseInstanceExpression Scoped() - { - return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Scoped); - } + public class BaseInverseInstanceExpression where TImpl : class + { + public BaseInverseInstanceExpression(ServiceRegistry parent) + { + Parent = parent; } - public class BaseInverseInstanceExpression where TImpl : class + protected ServiceRegistry Parent { get; } + + public virtual ScopedInverseInstanceExpression Named(string name) { - public BaseInverseInstanceExpression(ServiceRegistry parent) - { - Parent = parent; - } + return new ScopedInverseInstanceExpression(Parent, name); + } + + public virtual ScopedInverseInstanceExpression Singleton() + { + return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Singleton); + } + } - protected ServiceRegistry Parent { get; } + public class ScopedInverseInstanceExpression where TImpl : class + { + private readonly TImpl _providedInstance; + private readonly ServiceLifetime _lifetime; + private readonly string _name; + private readonly ServiceRegistry _parent; + private Instance _rootInstance; - public virtual ScopedInverseInstanceExpression Named(string name) - { - return new ScopedInverseInstanceExpression(Parent, name); - } + public ScopedInverseInstanceExpression(ServiceRegistry parent, string name) + { + _parent = parent; + _name = name; + } - public virtual ScopedInverseInstanceExpression Singleton() - { - return new ScopedInverseInstanceExpression(Parent, ServiceLifetime.Singleton); - } + public ScopedInverseInstanceExpression(ServiceRegistry parent, ServiceLifetime lifetime) + { + _parent = parent; + _lifetime = lifetime; } - public class ScopedInverseInstanceExpression where TImpl : class + public ScopedInverseInstanceExpression(ServiceRegistry parent, TImpl instance, string name) { - public ScopedInverseInstanceExpression(ServiceRegistry parent, string name) - { - _parent = parent; - _name = name; - } + _parent = parent; + _providedInstance = instance; + _name = name; + } - public ScopedInverseInstanceExpression(ServiceRegistry parent, ServiceLifetime lifetime) - { - _parent = parent; - _lifetime = lifetime; - } + public ScopedInverseInstanceExpression(ServiceRegistry parent, TImpl instance) + { + _parent = parent; + _providedInstance = instance; - public ScopedInverseInstanceExpression(ServiceRegistry parent, TImpl instance, string name) - { - _parent = parent; - _providedInstance = instance; - _name = name; - } + _lifetime = ServiceLifetime.Singleton; + } - public ScopedInverseInstanceExpression(ServiceRegistry parent, TImpl instance) + public ScopedInverseInstanceExpression For() + where TService : class + { + if (!typeof(TService).IsAssignableFrom(typeof(TImpl))) { - _parent = parent; - _providedInstance = instance; - - _lifetime = ServiceLifetime.Singleton; + throw new ArgumentException( + $"There is no conversion from {typeof(TImpl).Name} to {typeof(TImpl).Name}"); } - private readonly TImpl _providedInstance; - private ServiceRegistry _parent; - private string _name; - private ServiceLifetime _lifetime; - private Instance _rootInstance; + AddRootRegistration(); + + var instanceExpression = _parent.For(); + Instance instance; - public ScopedInverseInstanceExpression For() - where TService : class + if (string.IsNullOrEmpty(_name)) { - if (!typeof(TService).IsAssignableFrom(typeof(TImpl))) - { - throw new ArgumentException($"There is no conversion from {typeof(TImpl).Name} to {typeof(TImpl).Name}"); - } + instance = instanceExpression.Use(c => (TService)c.GetInstance(typeof(TImpl))); + } + else + { + instance = instanceExpression.Use(c => (TService)c.GetInstance(typeof(TImpl), _name)).Named(_name); + } - AddRootRegistration(); + instance.Lifetime = _lifetime; - var instanceExpression = _parent.For(); - Instance instance; + return this; + } - if (String.IsNullOrEmpty(_name)) + private void AddRootRegistration() + { + if (_rootInstance is null) + { + if (_providedInstance is null) { - instance = instanceExpression.Use(c => (TService)c.GetInstance(typeof(TImpl))); + _rootInstance = _parent.For().Use(); } else { - instance = instanceExpression.Use(c => (TService)c.GetInstance(typeof(TImpl), _name)).Named(_name); + _rootInstance = _parent.For().Use(_providedInstance); } - instance.Lifetime = _lifetime; - - return this; - } - - private void AddRootRegistration() - { - if (_rootInstance is null) + _rootInstance.Lifetime = _lifetime; + if (!string.IsNullOrEmpty(_name)) { - if (_providedInstance is null) - { - _rootInstance = _parent.For().Use(); - } - else - { - _rootInstance = _parent.For().Use(_providedInstance); - } - - _rootInstance.Lifetime = _lifetime; - if (!String.IsNullOrEmpty(_name)) - { - _rootInstance.Named(_name); - } + _rootInstance.Named(_name); } } } diff --git a/src/Lamar/ServiceRegistry.cs b/src/Lamar/ServiceRegistry.cs index 3a01a793..c8323b72 100644 --- a/src/Lamar/ServiceRegistry.cs +++ b/src/Lamar/ServiceRegistry.cs @@ -1,527 +1,559 @@ using System; using System.Collections.Generic; using System.Linq; +using JasperFx.Core.Reflection; using Lamar.IoC.Activation; using Lamar.IoC.Instances; using Lamar.IoC.Setters; using Lamar.Scanning.Conventions; -using JasperFx.CodeGeneration; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +public static class InstanceExtensions { - public static class InstanceExtensions + public static T Named(this T instance, string name) where T : Instance { - public static T Named(this T instance, string name) where T : Instance - { - instance.Name = name; - instance.IsExplicitlyNamed = true; - - return instance; - } + instance.Name = name; + instance.IsExplicitlyNamed = true; - public static T Scoped(this T instance) where T : Instance - { - AssertNotObjectInstance(instance); - instance.Lifetime = ServiceLifetime.Scoped; - return instance; - } + return instance; + } - private static void AssertNotObjectInstance(T instance) where T : Instance - { - if (instance is ObjectInstance) - throw new InvalidOperationException( - "You cannot override the lifecycle of a direct object registration. Did you mean to use a Lambda registration instead?"); - } + public static T Scoped(this T instance) where T : Instance + { + AssertNotObjectInstance(instance); + instance.Lifetime = ServiceLifetime.Scoped; + return instance; + } - public static T Singleton(this T instance) where T : Instance + private static void AssertNotObjectInstance(T instance) where T : Instance + { + if (instance is ObjectInstance) { - instance.Lifetime = ServiceLifetime.Singleton; - return instance; + throw new InvalidOperationException( + "You cannot override the lifecycle of a direct object registration. Did you mean to use a Lambda registration instead?"); } + } - public static T Transient(this T instance) where T : Instance - { - AssertNotObjectInstance(instance); - instance.Lifetime = ServiceLifetime.Transient; - return instance; - } + public static T Singleton(this T instance) where T : Instance + { + instance.Lifetime = ServiceLifetime.Singleton; + return instance; } - public partial class ServiceRegistry : List, IServiceCollection + public static T Transient(this T instance) where T : Instance { - public static ServiceRegistry For(Action configuration) - { - var registry = new ServiceRegistry(); - configuration(registry); + AssertNotObjectInstance(instance); + instance.Lifetime = ServiceLifetime.Transient; + return instance; + } +} - return registry; - } +public partial class ServiceRegistry : List, IServiceCollection +{ + public ServiceRegistry() + { + } - public ServiceRegistry() - { - } + public ServiceRegistry(IEnumerable descriptors) + { + AddRange(descriptors); + } - public ServiceRegistry(IEnumerable descriptors) - { - AddRange(descriptors); - } + internal IList RegistryTypes { get; set; } = new List(); - /// - /// This method is a shortcut for specifying the default constructor and - /// setter arguments for a ImplementationType. ForConcreteType is shorthand for: - /// For[T]().Use[T].************** - /// when the ServiceType and ImplementationType are the same Type - /// - /// - /// - public BuildWithExpression ForConcreteType() where T : class + /// + /// Configure Container-wide policies and conventions + /// + public PoliciesExpression Policies => new(this); + + public static ServiceRegistry For(Action configuration) + { + var registry = new ServiceRegistry(); + configuration(registry); + + return registry; + } + + /// + /// This method is a shortcut for specifying the default constructor and + /// setter arguments for a ImplementationType. ForConcreteType is shorthand for: + /// For[T]().Use[T].************** + /// when the ServiceType and ImplementationType are the same Type + /// + /// + /// + public BuildWithExpression ForConcreteType() where T : class + { + var instance = For().Use(); + return new BuildWithExpression(instance); + } + + + public InstanceExpression For() where T : class + { + return new InstanceExpression(this, ServiceLifetime.Transient); + } + + public DescriptorExpression For(Type serviceType) + { + return new DescriptorExpression(serviceType, this); + } + + /// + /// Shorthand equivalent to `For().******.Singleton()` + /// + /// + /// + public InstanceExpression ForSingletonOf() where T : class + { + return new InstanceExpression(this, ServiceLifetime.Singleton); + } + + /// + /// Create an isolated type scanning registration policy + /// + /// + public void Scan(Action scan) + { + var finder = new AssemblyScanner(this); + scan(finder); + + finder.Start(); + + var descriptor = ServiceDescriptor.Singleton(finder); + Add(descriptor); + } + + /// + /// Include the registrations from another ServiceRegistry + /// + /// + public void IncludeRegistry() where T : ServiceRegistry, new() + { + IncludeRegistry(new T()); + } + + /// + /// Include the registrations from another ServiceRegistry + /// + /// + /// + public void IncludeRegistry(T serviceRegistry) where T : ServiceRegistry + { + Include(serviceRegistry); + } + + /// + /// Include the registrations from another ServiceRegistry + /// + /// + /// + public void Include(ServiceRegistry registry) + { + if (registry == null) { - var instance = For().Use(); - return new BuildWithExpression(instance); + throw new ArgumentNullException(nameof(registry)); } - - /// - /// Define the constructor and setter arguments for the default T - /// - /// - public class BuildWithExpression + + var type = registry.GetType(); + if (type != typeof(ServiceRegistry)) { - public BuildWithExpression(ConstructorInstance instance) + if (RegistryTypes.Contains(type)) { - Configure = instance; + return; } - public ConstructorInstance Configure { get; } + AddRange(registry); + RegistryTypes.Add(type); + } + else + { + AddRange(registry); } + } + + /// + /// Tells Lamar that the service "T" will be injected into a built + /// container later. Used for framework support + /// + /// + public void Injectable() where T : class + { + For().Use(new InjectedInstance()); + } + + internal T[] FindAndRemovePolicies() where T : ILamarPolicy + { + var policies = this + .Where(x => x.ServiceType == typeof(T) && x.ImplementationInstance != null) + .Select(x => x.ImplementationInstance) + .OfType() + .ToArray(); + RemoveAll(x => x.ServiceType == typeof(T)); + return policies; + } + + public InverseInstanceExpression Use() where T : class + { + return new InverseInstanceExpression(this); + } + + public ProvidedInstanceInverseInstanceExpression Use(T instance) where T : class + { + return new ProvidedInstanceInverseInstanceExpression(this, instance); + } - public InstanceExpression For() where T : class + /// + /// Define the constructor and setter arguments for the default T + /// + /// + public class BuildWithExpression + { + public BuildWithExpression(ConstructorInstance instance) { - return new InstanceExpression(this, ServiceLifetime.Transient); + Configure = instance; } - public DescriptorExpression For(Type serviceType) + public ConstructorInstance Configure { get; } + } + + public class DescriptorExpression + { + private readonly ServiceRegistry _parent; + private readonly Type _serviceType; + + public DescriptorExpression(Type serviceType, ServiceRegistry parent) { - return new DescriptorExpression(serviceType, this); + _serviceType = serviceType; + _parent = parent; } - public class DescriptorExpression + public ConstructorInstance Use(Type concreteType) { - private readonly Type _serviceType; - private readonly ServiceRegistry _parent; - - public DescriptorExpression(Type serviceType, ServiceRegistry parent) - { - _serviceType = serviceType; - _parent = parent; - } - - public ConstructorInstance Use(Type concreteType) - { - var instance = new ConstructorInstance(_serviceType, concreteType, ServiceLifetime.Transient); - _parent.Add(instance); + var instance = new ConstructorInstance(_serviceType, concreteType, ServiceLifetime.Transient); + _parent.Add(instance); - return instance; - } + return instance; + } - public ConstructorInstance Add(Type implementationType) - { - var instance = new ConstructorInstance(_serviceType, implementationType, ServiceLifetime.Transient); - _parent.Add(instance); - return instance; - } + public ConstructorInstance Add(Type implementationType) + { + var instance = new ConstructorInstance(_serviceType, implementationType, ServiceLifetime.Transient); + _parent.Add(instance); + return instance; + } - /// - /// Register a custom Instance - /// - /// - /// - public void Use(Instance instance) + /// + /// Register a custom Instance + /// + /// + /// + public void Use(Instance instance) + { + if (instance.ServiceType != _serviceType) { - if (instance.ServiceType != _serviceType) - throw new ArgumentOutOfRangeException(nameof(instance), $"The Instance.ServiceType {instance.ServiceType.FullNameInCode()} was not {_serviceType.FullNameInCode()}"); - - _parent.Add(instance); + throw new ArgumentOutOfRangeException(nameof(instance), + $"The Instance.ServiceType {instance.ServiceType.FullNameInCode()} was not {_serviceType.FullNameInCode()}"); } - /// - /// Decorate all registrations to the service type with the supplied decorator type - /// - /// - public void DecorateAllWith(Type decoratorType) - { - var policy = new DecoratorPolicy(_serviceType, decoratorType); - _parent.Policies.DecorateWith(policy); - } + _parent.Add(instance); } - public class InstanceExpression where T : class + /// + /// Decorate all registrations to the service type with the supplied decorator type + /// + /// + public void DecorateAllWith(Type decoratorType) { - private readonly ServiceRegistry _parent; - private readonly ServiceLifetime? _lifetime; + var policy = new DecoratorPolicy(_serviceType, decoratorType); + _parent.Policies.DecorateWith(policy); + } + } - public InstanceExpression(ServiceRegistry parent, ServiceLifetime? lifetime) - { - _parent = parent; - _lifetime = lifetime; - } + public class InstanceExpression where T : class + { + private readonly ServiceLifetime? _lifetime; + private readonly ServiceRegistry _parent; + public InstanceExpression(ServiceRegistry parent, ServiceLifetime? lifetime) + { + _parent = parent; + _lifetime = lifetime; + } - public ConstructorInstance Use() where TConcrete : class, T + public ConstructorInstance Use() where TConcrete : class, T + { + var instance = ConstructorInstance.For(); + if (_lifetime != null) { - var instance = ConstructorInstance.For(); - if (_lifetime != null) instance.Lifetime = _lifetime.Value; - - _parent.Add(instance); - - return instance; + instance.Lifetime = _lifetime.Value; } - /// - /// Register a custom instance - /// - /// - public void Use(Instance instance) - { - if (_lifetime != null) - { - instance.Lifetime = _lifetime.Value; - } - - _parent.Add(instance); - } + _parent.Add(instance); - /// - /// Fills in a default type implementation for a service type if there are no prior - /// registrations - /// - /// - /// - public void UseIfNone() where TConcrete : class, T - { - if (_parent.FindDefault() == null) - { - Use(); - } - } + return instance; + } - /// - /// Fills in a default type implementation for a service type if there are no prior - /// registrations - /// - /// - public void UseIfNone(T service) + /// + /// Register a custom instance + /// + /// + public void Use(Instance instance) + { + if (_lifetime != null) { - if (_parent.FindDefault() == null) - { - Use(service); - } + instance.Lifetime = _lifetime.Value; } - /// - /// Delegates to Use<T>(), polyfill for StructureMap syntax - /// - /// - public ConstructorInstance Add() where TConcrete : class, T - { - return Use(); - } + _parent.Add(instance); + } - public ObjectInstance Use(T service) + /// + /// Fills in a default type implementation for a service type if there are no prior + /// registrations + /// + /// + /// + public void UseIfNone() where TConcrete : class, T + { + if (_parent.FindDefault() == null) { - var instance = new ObjectInstance(typeof(T), service); - _parent.Add(instance); - - return instance; + Use(); } + } - public ObjectInstance Add(T instance) + /// + /// Fills in a default type implementation for a service type if there are no prior + /// registrations + /// + /// + public void UseIfNone(T service) + { + if (_parent.FindDefault() == null) { - return Use(instance); + Use(service); } + } - public LambdaInstance Add(Func func) - { - var instance = LambdaInstance.For(func); - if (_lifetime != null) instance.Lifetime = _lifetime.Value; - - _parent.Add(instance); + /// + /// Delegates to Use<T>(), polyfill for StructureMap syntax + /// + /// + public ConstructorInstance Add() where TConcrete : class, T + { + return Use(); + } - return instance; + public ObjectInstance Use(T service) + { + var instance = new ObjectInstance(typeof(T), service); + _parent.Add(instance); - } - - public LambdaInstance Use(Func func) - { - return Add(func); + return instance; + } - } + public ObjectInstance Add(T instance) + { + return Use(instance); + } - /// - /// Decorates all instances of T with the concrete type TDecorator - /// - /// - public void DecorateAllWith() where TDecorator : T + public LambdaInstance Add(Func func) + { + var instance = LambdaInstance.For(func); + if (_lifetime != null) { - var policy = new DecoratorPolicy(typeof(T), typeof(TDecorator)); - _parent.AddSingleton(policy); + instance.Lifetime = _lifetime.Value; } - /// - /// Intercept the object being created and potentially replace it with a wrapped - /// version or another object. This will apply to every registration where the service - /// type is T or the implementation type could be cast to T - /// - /// - /// - public void InterceptAll(Func interceptor) - { - InterceptAll((s, x) => interceptor(x)); - } - - /// - /// Intercept the object being created and potentially replace it with a wrapped - /// version or another object. This will apply to every registration where the service - /// type is T or the implementation type could be cast to T - /// - /// - /// - public void InterceptAll(Func interceptor) - { - var policy = new InterceptorPolicy(interceptor); - _parent.Policies.Add(policy); - } - - /// - /// Perform some action on the object being created at the time the object is created for the first time by Lamar. - /// This will apply to every registration where the service - /// type is T or the implementation type could be cast to T - /// - /// - /// - public void OnCreationForAll(Action activator) - { - var policy = new ActivationPolicy(activator); - _parent.Policies.Add(policy); - } - - /// - /// Perform some action on the object being created at the time the object is created for the first time by Lamar. - /// This will apply to every registration where the service - /// type is T or the implementation type could be cast to T - /// - /// - /// - public void OnCreationForAll(Action activator) - { - OnCreationForAll((c, x) => activator(x)); - } + _parent.Add(instance); + + return instance; } - /// - /// Shorthand equivalent to `For().******.Singleton()` - /// - /// - /// - public InstanceExpression ForSingletonOf() where T : class + public LambdaInstance Use(Func func) { - return new InstanceExpression(this, ServiceLifetime.Singleton); + return Add(func); } /// - /// Create an isolated type scanning registration policy + /// Decorates all instances of T with the concrete type TDecorator /// - /// - public void Scan(Action scan) + /// + public void DecorateAllWith() where TDecorator : T { - var finder = new AssemblyScanner(this); - scan(finder); - - finder.Start(); - - var descriptor = ServiceDescriptor.Singleton(finder); - Add(descriptor); + var policy = new DecoratorPolicy(typeof(T), typeof(TDecorator)); + _parent.AddSingleton(policy); } - internal IList RegistryTypes { get; set; } = new List(); - /// - /// Include the registrations from another ServiceRegistry + /// Intercept the object being created and potentially replace it with a wrapped + /// version or another object. This will apply to every registration where the service + /// type is T or the implementation type could be cast to T /// - /// - public void IncludeRegistry() where T : ServiceRegistry, new() + /// + /// + public void InterceptAll(Func interceptor) { - IncludeRegistry(new T()); + InterceptAll((s, x) => interceptor(x)); } /// - /// Include the registrations from another ServiceRegistry + /// Intercept the object being created and potentially replace it with a wrapped + /// version or another object. This will apply to every registration where the service + /// type is T or the implementation type could be cast to T /// - /// - /// - public void IncludeRegistry(T serviceRegistry) where T : ServiceRegistry + /// + /// + public void InterceptAll(Func interceptor) { - Include(serviceRegistry); + var policy = new InterceptorPolicy(interceptor); + _parent.Policies.Add(policy); } /// - /// Include the registrations from another ServiceRegistry + /// Perform some action on the object being created at the time the object is created for the first time by Lamar. + /// This will apply to every registration where the service + /// type is T or the implementation type could be cast to T /// - /// - /// - public void Include(ServiceRegistry registry) + /// + /// + public void OnCreationForAll(Action activator) { - if (registry == null) throw new ArgumentNullException(nameof(registry)); - var type = registry.GetType(); - if (type != typeof(ServiceRegistry)) - { - if (RegistryTypes.Contains(type)) return; - - this.AddRange(registry); - RegistryTypes.Add(type); - } - else - { - this.AddRange(registry); - } + var policy = new ActivationPolicy(activator); + _parent.Policies.Add(policy); } /// - /// Configure Container-wide policies and conventions + /// Perform some action on the object being created at the time the object is created for the first time by Lamar. + /// This will apply to every registration where the service + /// type is T or the implementation type could be cast to T /// - public PoliciesExpression Policies => new PoliciesExpression(this); - - public class PoliciesExpression + /// + /// + public void OnCreationForAll(Action activator) { - private readonly ServiceRegistry _parent; + OnCreationForAll((c, x) => activator(x)); + } + } + public class PoliciesExpression + { + private readonly ServiceRegistry _parent; - internal PoliciesExpression(ServiceRegistry parent) - { - _parent = parent; - } - /// - /// Adds a new policy to this container - /// that can apply to every object instance created - /// by this container - /// - /// - public void Add(ILamarPolicy policy) - { - if (policy is IInstancePolicy ip) _parent.AddSingleton(ip); - if (policy is IFamilyPolicy fp) _parent.AddSingleton(fp); - if (policy is IRegistrationPolicy rp) _parent.AddSingleton(rp); - if (policy is IDecoratorPolicy dp) _parent.AddSingleton(dp); - if (policy is ISetterPolicy sp) _parent.AddSingleton(sp); - } + internal PoliciesExpression(ServiceRegistry parent) + { + _parent = parent; + } - /// - /// Adds a new policy to this container - /// that can apply to every object instance created - /// by this container - /// - public void Add() where T : ILamarPolicy, new() + /// + /// Adds a new policy to this container + /// that can apply to every object instance created + /// by this container + /// + /// + public void Add(ILamarPolicy policy) + { + if (policy is IInstancePolicy ip) { - Add(new T()); + _parent.AddSingleton(ip); } - - /// - /// Register a strategy for automatically resolving "missing" families - /// when an unknown ServiceType is first encountered - /// - /// - public void OnMissingFamily(IFamilyPolicy policy) + if (policy is IFamilyPolicy fp) { - _parent.AddSingleton(policy); + _parent.AddSingleton(fp); } - public void OnMissingFamily() where T : IFamilyPolicy, new() + if (policy is IRegistrationPolicy rp) { - OnMissingFamily(new T()); + _parent.AddSingleton(rp); } - /// - /// Register a strategy for applying decorators on existing registrations - /// - /// - public void DecorateWith() where T : IDecoratorPolicy, new() + if (policy is IDecoratorPolicy dp) { - DecorateWith(new T()); + _parent.AddSingleton(dp); } - public void DecorateWith(IDecoratorPolicy policy) + if (policy is ISetterPolicy sp) { - _parent.AddSingleton(policy); + _parent.AddSingleton(sp); } + } - /// - /// Creates automatic "policies" for which public setters are considered mandatory - /// properties by StructureMap that will be "setter injected" as part of the - /// construction process. - /// - /// - public void SetAllProperties(Action action) - { - var convention = new SetterConvention(this); - action(convention); - } + /// + /// Adds a new policy to this container + /// that can apply to every object instance created + /// by this container + /// + public void Add() where T : ILamarPolicy, new() + { + Add(new T()); + } - /// - /// Directs StructureMap to always inject dependencies into any and all public Setter properties - /// of the type TServiceType. - /// - /// - /// - public InstanceExpression FillAllPropertiesOfType() where TType : class - { - Add(new LambdaSetterPolicy(prop => prop.PropertyType == typeof(TType))); - return _parent.For(); - } + /// + /// Register a strategy for automatically resolving "missing" families + /// when an unknown ServiceType is first encountered + /// + /// + public void OnMissingFamily(IFamilyPolicy policy) + { + _parent.AddSingleton(policy); + } + + public void OnMissingFamily() where T : IFamilyPolicy, new() + { + OnMissingFamily(new T()); } /// - /// Tells Lamar that the service "T" will be injected into a built - /// container later. Used for framework support + /// Register a strategy for applying decorators on existing registrations /// /// - public void Injectable() where T : class + public void DecorateWith() where T : IDecoratorPolicy, new() { - For().Use(new InjectedInstance()); + DecorateWith(new T()); } - internal T[] FindAndRemovePolicies() where T : ILamarPolicy + public void DecorateWith(IDecoratorPolicy policy) { - var policies = this - .Where(x => x.ServiceType == typeof(T) && x.ImplementationInstance != null) - .Select(x => x.ImplementationInstance) - .OfType() - .ToArray(); - - RemoveAll(x => x.ServiceType == typeof(T)); - - return policies; + _parent.AddSingleton(policy); } - public InverseInstanceExpression Use() where T : class + /// + /// Creates automatic "policies" for which public setters are considered mandatory + /// properties by StructureMap that will be "setter injected" as part of the + /// construction process. + /// + /// + public void SetAllProperties(Action action) { - return new InverseInstanceExpression(this); + var convention = new SetterConvention(this); + action(convention); } - public ProvidedInstanceInverseInstanceExpression Use(T instance) where T : class + /// + /// Directs StructureMap to always inject dependencies into any and all public Setter properties + /// of the type TServiceType. + /// + /// + /// + public InstanceExpression FillAllPropertiesOfType() where TType : class { - return new ProvidedInstanceInverseInstanceExpression(this, instance); - } - } + Add(new LambdaSetterPolicy(prop => prop.PropertyType == typeof(TType))); - public enum DynamicAssemblySharing - { - Shared, - Individual + return _parent.For(); + } } } + +public enum DynamicAssemblySharing +{ + Shared, + Individual +} \ No newline at end of file diff --git a/src/Lamar/SetterPropertyAttribute.cs b/src/Lamar/SetterPropertyAttribute.cs index e96a6f04..e0970dc5 100644 --- a/src/Lamar/SetterPropertyAttribute.cs +++ b/src/Lamar/SetterPropertyAttribute.cs @@ -1,12 +1,11 @@ using System; -namespace Lamar +namespace Lamar; + +/// +/// Marks a Property in a concrete class as filled by setter injection +/// +[AttributeUsage(AttributeTargets.Property)] +public class SetterPropertyAttribute : Attribute { - /// - /// Marks a Property in a concrete class as filled by setter injection - /// - [AttributeUsage(AttributeTargets.Property)] - public class SetterPropertyAttribute : Attribute - { - } } \ No newline at end of file diff --git a/src/Lamar/SingletonAttribute.cs b/src/Lamar/SingletonAttribute.cs index 7260de23..eecd41b3 100644 --- a/src/Lamar/SingletonAttribute.cs +++ b/src/Lamar/SingletonAttribute.cs @@ -2,20 +2,21 @@ using Lamar.IoC.Instances; using Microsoft.Extensions.DependencyInjection; -namespace Lamar +namespace Lamar; + +#region sample_SingletonAttribute + +/// +/// Makes Lamar treat a Type as a singleton in the lifecycle scoping +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] +public class SingletonAttribute : LamarAttribute { - #region sample_SingletonAttribute - /// - /// Makes Lamar treat a Type as a singleton in the lifecycle scoping - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] - public class SingletonAttribute : LamarAttribute + // This method will affect single registrations + public override void Alter(IConfiguredInstance instance) { - // This method will affect single registrations - public override void Alter(IConfiguredInstance instance) - { - instance.Lifetime = ServiceLifetime.Singleton; - } + instance.Lifetime = ServiceLifetime.Singleton; } - #endregion -} \ No newline at end of file +} + +#endregion \ No newline at end of file diff --git a/src/Lamar/Util/TypeExtensions.cs b/src/Lamar/Util/TypeExtensions.cs index c64f8df7..ca7b40c4 100644 --- a/src/Lamar/Util/TypeExtensions.cs +++ b/src/Lamar/Util/TypeExtensions.cs @@ -7,20 +7,39 @@ namespace Lamar.Util; internal static class TypeExtensions { - private readonly static Type[] _ignoredTypes = new[] { typeof(Uri), typeof(TimeSpan), typeof(DateTimeOffset) }; - + private static readonly Type[] _ignoredTypes = { typeof(Uri), typeof(TimeSpan), typeof(DateTimeOffset) }; + internal static bool ShouldIgnore(this Type type) { - if (type.IsSimple()) return true; + if (type.IsSimple()) + { + return true; + } + + if (type.IsEnum) + { + return true; + } - if (type.IsEnum) return true; + if (_ignoredTypes.Contains(type)) + { + return true; + } - if (_ignoredTypes.Contains(type)) return true; - if (type.IsNullable() && _ignoredTypes.Contains(type.GetGenericArguments().First())) return true; + if (type.IsNullable() && _ignoredTypes.Contains(type.GetGenericArguments().First())) + { + return true; + } - if (type.CanBeCastTo()) return true; + if (type.CanBeCastTo()) + { + return true; + } - if (type.IsDateTime()) return true; + if (type.IsDateTime()) + { + return true; + } return false; } diff --git a/src/Lamar/ValidationMethodAttribute.cs b/src/Lamar/ValidationMethodAttribute.cs index d5118da6..5904004e 100644 --- a/src/Lamar/ValidationMethodAttribute.cs +++ b/src/Lamar/ValidationMethodAttribute.cs @@ -2,52 +2,50 @@ using System.Collections.Generic; using System.Reflection; using JasperFx.Core.Reflection; -using JasperFx.CodeGeneration.Util; -namespace Lamar +namespace Lamar; + +/// +/// Marks a method with no parameters as a method that validates an instance. StructureMap +/// uses this method to validate the configuration file. If the method does not throw an +/// exception, the object is assumed to be valid. +/// +[AttributeUsage(AttributeTargets.Method)] +public class ValidationMethodAttribute : Attribute { /// - /// Marks a method with no parameters as a method that validates an instance. StructureMap - /// uses this method to validate the configuration file. If the method does not throw an - /// exception, the object is assumed to be valid. + /// Returns an array of any MethodInfo's on a Type that are marked as ValidationMethod /// - [AttributeUsage(AttributeTargets.Method)] - public class ValidationMethodAttribute : Attribute + /// CLR Type to search for validation methods + /// + public static MethodInfo[] GetValidationMethods(Type objectType) { - /// - /// Returns an array of any MethodInfo's on a Type that are marked as ValidationMethod - /// - /// CLR Type to search for validation methods - /// - public static MethodInfo[] GetValidationMethods(Type objectType) - { - var methodList = new List(); - - var methods = objectType.GetMethods(); - foreach (var method in methods) - { - var att = method.GetAttribute(); - + var methodList = new List(); - if (att == null) - { - continue; - } + var methods = objectType.GetMethods(); + foreach (var method in methods) + { + var att = method.GetAttribute(); - if (method.GetParameters().Length > 0) - { - var msg = - $"Method *{method.Name}* in Class *{objectType.AssemblyQualifiedName}* cannot be a validation method because it has parameters"; - throw new ArgumentException(msg); - } - methodList.Add(method); + if (att == null) + { + continue; } - var returnValue = new MethodInfo[methodList.Count]; - methodList.CopyTo(returnValue, 0); + if (method.GetParameters().Length > 0) + { + var msg = + $"Method *{method.Name}* in Class *{objectType.AssemblyQualifiedName}* cannot be a validation method because it has parameters"; + throw new ArgumentException(msg); + } - return returnValue; + methodList.Add(method); } + + var returnValue = new MethodInfo[methodList.Count]; + methodList.CopyTo(returnValue, 0); + + return returnValue; } } \ No newline at end of file