Makes Container.CreateInstance into an extension

This commit is contained in:
Lars-Erik Aabech
2018-10-26 21:14:19 +02:00
parent eee7222e0b
commit c967d6a0fc
3 changed files with 40 additions and 40 deletions

View File

@@ -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<TBuilder>();
}
/// <summary>
/// Creates an instance of a service, with arguments.
/// </summary>
/// <param name="container"></param>
/// <param name="type">The type of the instance.</param>
/// <param name="args">Named arguments.</param>
/// <returns>An instance of the specified type.</returns>
/// <remarks>
/// <para>The instance type does not need to be registered into the container.</para>
/// <para>The arguments are used as dependencies by the container. Other dependencies
/// are retrieved from the container.</para>
/// </remarks>
public static object CreateInstance(this IContainer container, Type type, IDictionary<string, object> 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);
}
}
}

View File

@@ -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
/// <returns>The registrations for the service.</returns>
IEnumerable<Registration> GetRegistered(Type serviceType);
/// <summary>
/// Creates an instance of a service, with arguments.
/// </summary>
/// <param name="type">The type of the instance.</param>
/// <param name="args">Named arguments.</param>
/// <returns>An instance of the specified type.</returns>
/// <remarks>
/// <para>The instance type does not need to be registered into the container.</para>
/// <para>The arguments are used as dependencies by the container. Other dependencies
/// are retrieved from the container.</para>
/// </remarks>
object CreateInstance(Type type, IDictionary<string, object> args);
/// <summary>
/// Releases an instance.
/// </summary>

View File

@@ -125,33 +125,6 @@ namespace Umbraco.Core.Composing.LightInject
public IEnumerable<Registration> GetRegistered(Type type)
=> Container.AvailableServices.Where(x => x.ServiceType == type).Select(x => new Registration(x.ServiceType, x.ServiceName));
/// <inheritdoc />
public object CreateInstance(Type type, IDictionary<string, object> 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);
}
/// <inheritdoc />
public void Release(object instance)
{