From c967d6a0fcd25a87ca91df85b0a0385e4dd4b2bb Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Fri, 26 Oct 2018 21:14:19 +0200 Subject: [PATCH] Makes Container.CreateInstance into an extension --- .../Composing/ContainerExtensions.cs | 39 +++++++++++++++++++ src/Umbraco.Core/Composing/IContainer.cs | 14 +------ .../LightInject/LightInjectContainer.cs | 27 ------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Core/Composing/ContainerExtensions.cs b/src/Umbraco.Core/Composing/ContainerExtensions.cs index 86e18db35b..36af613e55 100644 --- a/src/Umbraco.Core/Composing/ContainerExtensions.cs +++ b/src/Umbraco.Core/Composing/ContainerExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Reflection; namespace Umbraco.Core.Composing { @@ -172,5 +173,43 @@ namespace Umbraco.Core.Composing // initialize and return the builder return container.GetInstance(); } + + /// + /// Creates an instance of a service, with arguments. + /// + /// + /// The type of the instance. + /// Named arguments. + /// An instance of the specified type. + /// + /// The instance type does not need to be registered into the container. + /// The arguments are used as dependencies by the container. Other dependencies + /// are retrieved from the container. + /// + public static object CreateInstance(this IContainer container, Type type, IDictionary args) + { + // LightInject has this, but then it requires RegisterConstructorDependency etc and has various oddities + // including the most annoying one, which is that it does not work on singletons (hard to fix) + //return Container.GetInstance(type, args); + + // this method is essentially used to build singleton instances, so it is assumed that it would be + // more expensive to build and cache a dynamic method ctor than to simply invoke the ctor, as we do + // here - this can be discussed + + var ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).OrderByDescending(x => x.GetParameters().Length).FirstOrDefault(); + if (ctor == null) throw new InvalidOperationException($"Could not find a public constructor for type {type.FullName}."); + + var ctorParameters = ctor.GetParameters(); + var ctorArgs = new object[ctorParameters.Length]; + var i = 0; + foreach (var parameter in ctorParameters) + { + // no! IsInstanceOfType is not ok here + // ReSharper disable once UseMethodIsInstanceOfType + var arg = args?.Values.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); + ctorArgs[i++] = arg ?? container.GetInstance(parameter.ParameterType); + } + return ctor.Invoke(ctorArgs); + } } } diff --git a/src/Umbraco.Core/Composing/IContainer.cs b/src/Umbraco.Core/Composing/IContainer.cs index 78137eb990..1780516c76 100644 --- a/src/Umbraco.Core/Composing/IContainer.cs +++ b/src/Umbraco.Core/Composing/IContainer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Umbraco.Core.Composing.LightInject; namespace Umbraco.Core.Composing { @@ -77,19 +78,6 @@ namespace Umbraco.Core.Composing /// The registrations for the service. IEnumerable GetRegistered(Type serviceType); - /// - /// Creates an instance of a service, with arguments. - /// - /// The type of the instance. - /// Named arguments. - /// An instance of the specified type. - /// - /// The instance type does not need to be registered into the container. - /// The arguments are used as dependencies by the container. Other dependencies - /// are retrieved from the container. - /// - object CreateInstance(Type type, IDictionary args); - /// /// Releases an instance. /// diff --git a/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs b/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs index dca07938cc..34bd2f1499 100644 --- a/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs +++ b/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs @@ -125,33 +125,6 @@ namespace Umbraco.Core.Composing.LightInject public IEnumerable GetRegistered(Type type) => Container.AvailableServices.Where(x => x.ServiceType == type).Select(x => new Registration(x.ServiceType, x.ServiceName)); - /// - public object CreateInstance(Type type, IDictionary args) - { - // LightInject has this, but then it requires RegisterConstructorDependency etc and has various oddities - // including the most annoying one, which is that it does not work on singletons (hard to fix) - //return Container.GetInstance(type, args); - - // this method is essentially used to build singleton instances, so it is assumed that it would be - // more expensive to build and cache a dynamic method ctor than to simply invoke the ctor, as we do - // here - this can be discussed - - var ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).OrderByDescending(x => x.GetParameters().Length).FirstOrDefault(); - if (ctor == null) throw new InvalidOperationException($"Could not find a public constructor for type {type.FullName}."); - - var ctorParameters = ctor.GetParameters(); - var ctorArgs = new object[ctorParameters.Length]; - var i = 0; - foreach (var parameter in ctorParameters) - { - // no! IsInstanceOfType is not ok here - // ReSharper disable once UseMethodIsInstanceOfType - var arg = args?.Values.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); - ctorArgs[i++] = arg ?? GetInstance(parameter.ParameterType); - } - return ctor.Invoke(ctorArgs); - } - /// public void Release(object instance) {