Codingstyle nullable
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,34 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Generic Constraint Registration Exception.
|
||||
/// </summary>
|
||||
/// <seealso cref="Exception" />
|
||||
public class DependencyContainerRegistrationException : Exception {
|
||||
private const String ConvertErrorText = "Cannot convert current registration of {0} to {1}";
|
||||
private const String RegisterErrorText = "Cannot register type {0} - abstract classes or interfaces are not valid implementation types for {1}.";
|
||||
private const String ErrorText = "Duplicate implementation of type {0} found ({1}).";
|
||||
|
||||
/// <summary>
|
||||
/// Generic Constraint Registration Exception.
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerRegistrationException"/> class.
|
||||
/// </summary>
|
||||
/// <seealso cref="Exception" />
|
||||
public class DependencyContainerRegistrationException : Exception
|
||||
{
|
||||
private const string ConvertErrorText = "Cannot convert current registration of {0} to {1}";
|
||||
private const string RegisterErrorText =
|
||||
"Cannot register type {0} - abstract classes or interfaces are not valid implementation types for {1}.";
|
||||
private const string ErrorText = "Duplicate implementation of type {0} found ({1}).";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerRegistrationException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registerType">Type of the register.</param>
|
||||
/// <param name="types">The types.</param>
|
||||
public DependencyContainerRegistrationException(Type registerType, IEnumerable<Type> types)
|
||||
: base(string.Format(ErrorText, registerType, GetTypesString(types)))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerRegistrationException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="method">The method.</param>
|
||||
/// <param name="isTypeFactory">if set to <c>true</c> [is type factory].</param>
|
||||
public DependencyContainerRegistrationException(Type type, string method, bool isTypeFactory = false)
|
||||
: base(isTypeFactory
|
||||
? string.Format(RegisterErrorText, type.FullName, method)
|
||||
: string.Format(ConvertErrorText, type.FullName, method))
|
||||
{
|
||||
}
|
||||
|
||||
private static string GetTypesString(IEnumerable<Type> types)
|
||||
{
|
||||
return string.Join(",", types.Select(type => type.FullName));
|
||||
}
|
||||
}
|
||||
/// <param name="registerType">Type of the register.</param>
|
||||
/// <param name="types">The types.</param>
|
||||
public DependencyContainerRegistrationException(Type registerType, IEnumerable<Type> types) : base(String.Format(ErrorText, registerType, GetTypesString(types))) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerRegistrationException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="method">The method.</param>
|
||||
/// <param name="isTypeFactory">if set to <c>true</c> [is type factory].</param>
|
||||
public DependencyContainerRegistrationException(Type type, String method, Boolean isTypeFactory = false) : base(isTypeFactory ? String.Format(RegisterErrorText, type.FullName, method) : String.Format(ConvertErrorText, type.FullName, method)) {
|
||||
}
|
||||
|
||||
private static String GetTypesString(IEnumerable<Type> types) => String.Join(",", types.Select(type => type.FullName));
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,25 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
|
||||
using System;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// An exception for dependency resolutions.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class DependencyContainerResolutionException : Exception {
|
||||
/// <summary>
|
||||
/// An exception for dependency resolutions.
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerResolutionException"/> class.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class DependencyContainerResolutionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerResolutionException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
public DependencyContainerResolutionException(Type type)
|
||||
: base($"Unable to resolve type: {type.FullName}")
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerResolutionException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="innerException">The inner exception.</param>
|
||||
public DependencyContainerResolutionException(Type type, Exception innerException)
|
||||
: base($"Unable to resolve type: {type.FullName}", innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <param name="type">The type.</param>
|
||||
public DependencyContainerResolutionException(Type type) : base($"Unable to resolve type: {type.FullName}") {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerResolutionException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="innerException">The inner exception.</param>
|
||||
public DependencyContainerResolutionException(Type type, Exception innerException) : base($"Unable to resolve type: {type.FullName}", innerException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +1,106 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Resolution settings.
|
||||
/// </summary>
|
||||
public class DependencyContainerResolveOptions {
|
||||
/// <summary>
|
||||
/// Resolution settings.
|
||||
/// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found).
|
||||
/// </summary>
|
||||
public class DependencyContainerResolveOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found).
|
||||
/// </summary>
|
||||
public static DependencyContainerResolveOptions Default { get; } = new DependencyContainerResolveOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unregistered resolution action.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The unregistered resolution action.
|
||||
/// </value>
|
||||
public DependencyContainerUnregisteredResolutionAction UnregisteredResolutionAction { get; set; } =
|
||||
DependencyContainerUnregisteredResolutionAction.AttemptResolve;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the named resolution failure action.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The named resolution failure action.
|
||||
/// </value>
|
||||
public DependencyContainerNamedResolutionFailureAction NamedResolutionFailureAction { get; set; } =
|
||||
DependencyContainerNamedResolutionFailureAction.Fail;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the constructor parameters.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The constructor parameters.
|
||||
/// </value>
|
||||
public Dictionary<string, object> ConstructorParameters { get; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Clones this instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DependencyContainerResolveOptions Clone() => new DependencyContainerResolveOptions
|
||||
{
|
||||
NamedResolutionFailureAction = NamedResolutionFailureAction,
|
||||
UnregisteredResolutionAction = UnregisteredResolutionAction,
|
||||
};
|
||||
}
|
||||
|
||||
public static DependencyContainerResolveOptions Default { get; } = new DependencyContainerResolveOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Defines Resolution actions.
|
||||
/// Gets or sets the unregistered resolution action.
|
||||
/// </summary>
|
||||
public enum DependencyContainerUnregisteredResolutionAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempt to resolve type, even if the type isn't registered.
|
||||
///
|
||||
/// Registered types/options will always take precedence.
|
||||
/// </summary>
|
||||
AttemptResolve,
|
||||
|
||||
/// <summary>
|
||||
/// Fail resolution if type not explicitly registered
|
||||
/// </summary>
|
||||
Fail,
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to resolve unregistered type if requested type is generic
|
||||
/// and no registration exists for the specific generic parameters used.
|
||||
///
|
||||
/// Registered types/options will always take precedence.
|
||||
/// </summary>
|
||||
GenericsOnly,
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The unregistered resolution action.
|
||||
/// </value>
|
||||
public DependencyContainerUnregisteredResolutionAction UnregisteredResolutionAction { get; set; } = DependencyContainerUnregisteredResolutionAction.AttemptResolve;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates failure actions.
|
||||
/// Gets or sets the named resolution failure action.
|
||||
/// </summary>
|
||||
public enum DependencyContainerNamedResolutionFailureAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The attempt unnamed resolution
|
||||
/// </summary>
|
||||
AttemptUnnamedResolution,
|
||||
|
||||
/// <summary>
|
||||
/// The fail
|
||||
/// </summary>
|
||||
Fail,
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The named resolution failure action.
|
||||
/// </value>
|
||||
public DependencyContainerNamedResolutionFailureAction NamedResolutionFailureAction { get; set; } = DependencyContainerNamedResolutionFailureAction.Fail;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates duplicate definition actions.
|
||||
/// Gets the constructor parameters.
|
||||
/// </summary>
|
||||
public enum DependencyContainerDuplicateImplementationAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The register single
|
||||
/// </summary>
|
||||
RegisterSingle,
|
||||
|
||||
/// <summary>
|
||||
/// The register multiple
|
||||
/// </summary>
|
||||
RegisterMultiple,
|
||||
|
||||
/// <summary>
|
||||
/// The fail
|
||||
/// </summary>
|
||||
Fail,
|
||||
}
|
||||
/// <value>
|
||||
/// The constructor parameters.
|
||||
/// </value>
|
||||
public Dictionary<System.String, System.Object> ConstructorParameters { get; } = new Dictionary<System.String, System.Object>();
|
||||
|
||||
/// <summary>
|
||||
/// Clones this instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DependencyContainerResolveOptions Clone() => new DependencyContainerResolveOptions {
|
||||
NamedResolutionFailureAction = NamedResolutionFailureAction,
|
||||
UnregisteredResolutionAction = UnregisteredResolutionAction,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines Resolution actions.
|
||||
/// </summary>
|
||||
public enum DependencyContainerUnregisteredResolutionAction {
|
||||
/// <summary>
|
||||
/// Attempt to resolve type, even if the type isn't registered.
|
||||
///
|
||||
/// Registered types/options will always take precedence.
|
||||
/// </summary>
|
||||
AttemptResolve,
|
||||
|
||||
/// <summary>
|
||||
/// Fail resolution if type not explicitly registered
|
||||
/// </summary>
|
||||
Fail,
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to resolve unregistered type if requested type is generic
|
||||
/// and no registration exists for the specific generic parameters used.
|
||||
///
|
||||
/// Registered types/options will always take precedence.
|
||||
/// </summary>
|
||||
GenericsOnly,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates failure actions.
|
||||
/// </summary>
|
||||
public enum DependencyContainerNamedResolutionFailureAction {
|
||||
/// <summary>
|
||||
/// The attempt unnamed resolution
|
||||
/// </summary>
|
||||
AttemptUnnamedResolution,
|
||||
|
||||
/// <summary>
|
||||
/// The fail
|
||||
/// </summary>
|
||||
Fail,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates duplicate definition actions.
|
||||
/// </summary>
|
||||
public enum DependencyContainerDuplicateImplementationAction {
|
||||
/// <summary>
|
||||
/// The register single
|
||||
/// </summary>
|
||||
RegisterSingle,
|
||||
|
||||
/// <summary>
|
||||
/// The register multiple
|
||||
/// </summary>
|
||||
RegisterMultiple,
|
||||
|
||||
/// <summary>
|
||||
/// The fail
|
||||
/// </summary>
|
||||
Fail,
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,18 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
|
||||
using System;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Weak Reference Exception.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
public class DependencyContainerWeakReferenceException : Exception {
|
||||
private const String ErrorText = "Unable to instantiate {0} - referenced object has been reclaimed";
|
||||
|
||||
/// <summary>
|
||||
/// Weak Reference Exception.
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerWeakReferenceException"/> class.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
public class DependencyContainerWeakReferenceException : Exception
|
||||
{
|
||||
private const string ErrorText = "Unable to instantiate {0} - referenced object has been reclaimed";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DependencyContainerWeakReferenceException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
public DependencyContainerWeakReferenceException(Type type)
|
||||
: base(string.Format(ErrorText, type.FullName))
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <param name="type">The type.</param>
|
||||
public DependencyContainerWeakReferenceException(Type type) : base(String.Format(ErrorText, type.FullName)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,423 +1,352 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Represents an abstract class for Object Factory.
|
||||
/// </summary>
|
||||
public abstract class ObjectFactoryBase {
|
||||
/// <summary>
|
||||
/// Represents an abstract class for Object Factory.
|
||||
/// Whether to assume this factory successfully constructs its objects
|
||||
///
|
||||
/// Generally set to true for delegate style factories as CanResolve cannot delve
|
||||
/// into the delegates they contain.
|
||||
/// </summary>
|
||||
public abstract class ObjectFactoryBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to assume this factory successfully constructs its objects
|
||||
///
|
||||
/// Generally set to true for delegate style factories as CanResolve cannot delve
|
||||
/// into the delegates they contain.
|
||||
/// </summary>
|
||||
public virtual bool AssumeConstruction => false;
|
||||
|
||||
/// <summary>
|
||||
/// The type the factory instantiates.
|
||||
/// </summary>
|
||||
public abstract Type CreatesType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to use, if specified.
|
||||
/// </summary>
|
||||
public ConstructorInfo Constructor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton variant.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The singleton variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">singleton.</exception>
|
||||
public virtual ObjectFactoryBase SingletonVariant =>
|
||||
throw new DependencyContainerRegistrationException(GetType(), "singleton");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the multi instance variant.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The multi instance variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">multi-instance.</exception>
|
||||
public virtual ObjectFactoryBase MultiInstanceVariant =>
|
||||
throw new DependencyContainerRegistrationException(GetType(), "multi-instance");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the strong reference variant.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The strong reference variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">strong reference.</exception>
|
||||
public virtual ObjectFactoryBase StrongReferenceVariant =>
|
||||
throw new DependencyContainerRegistrationException(GetType(), "strong reference");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the weak reference variant.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The weak reference variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">weak reference.</exception>
|
||||
public virtual ObjectFactoryBase WeakReferenceVariant =>
|
||||
throw new DependencyContainerRegistrationException(GetType(), "weak reference");
|
||||
|
||||
/// <summary>
|
||||
/// Create the type.
|
||||
/// </summary>
|
||||
/// <param name="requestedType">Type user requested to be resolved.</param>
|
||||
/// <param name="container">Container that requested the creation.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns> Instance of type. </returns>
|
||||
public abstract object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the factory for child container.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="child">The child.</param>
|
||||
/// <returns></returns>
|
||||
public virtual ObjectFactoryBase GetFactoryForChildContainer(
|
||||
Type type,
|
||||
DependencyContainer parent,
|
||||
DependencyContainer child)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Boolean AssumeConstruction => false;
|
||||
|
||||
/// <summary>
|
||||
/// IObjectFactory that creates new instances of types for each resolution.
|
||||
/// The type the factory instantiates.
|
||||
/// </summary>
|
||||
internal class MultiInstanceFactory : ObjectFactoryBase
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
|
||||
public MultiInstanceFactory(Type registerType, Type registerImplementation)
|
||||
{
|
||||
if (registerImplementation.IsAbstract || registerImplementation.IsInterface)
|
||||
{
|
||||
throw new DependencyContainerRegistrationException(registerImplementation,
|
||||
"MultiInstanceFactory",
|
||||
true);
|
||||
}
|
||||
|
||||
if (!DependencyContainer.IsValidAssignment(registerType, registerImplementation))
|
||||
{
|
||||
throw new DependencyContainerRegistrationException(registerImplementation,
|
||||
"MultiInstanceFactory",
|
||||
true);
|
||||
}
|
||||
|
||||
_registerType = registerType;
|
||||
_registerImplementation = registerImplementation;
|
||||
}
|
||||
|
||||
public override Type CreatesType => _registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase SingletonVariant =>
|
||||
new SingletonFactory(_registerType, _registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant => this;
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
return container.RegisteredTypes.ConstructType(_registerImplementation, Constructor, options);
|
||||
}
|
||||
catch (DependencyContainerResolutionException ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(_registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Type CreatesType {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IObjectFactory that invokes a specified delegate to construct the object.
|
||||
/// Constructor to use, if specified.
|
||||
/// </summary>
|
||||
internal class DelegateFactory : ObjectFactoryBase
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
|
||||
private readonly Func<DependencyContainer, Dictionary<string, object>, object> _factory;
|
||||
|
||||
public DelegateFactory(
|
||||
Type registerType,
|
||||
Func<DependencyContainer, Dictionary<string, object>, object> factory)
|
||||
{
|
||||
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
_registerType = registerType;
|
||||
}
|
||||
|
||||
public override bool AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => _registerType;
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => new WeakDelegateFactory(_registerType, _factory);
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant => this;
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _factory.Invoke(container, options.ConstructorParameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(_registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConstructorInfo Constructor {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IObjectFactory that invokes a specified delegate to construct the object
|
||||
/// Holds the delegate using a weak reference.
|
||||
/// Gets the singleton variant.
|
||||
/// </summary>
|
||||
internal class WeakDelegateFactory : ObjectFactoryBase
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
|
||||
private readonly WeakReference _factory;
|
||||
|
||||
public WeakDelegateFactory(
|
||||
Type registerType,
|
||||
Func<DependencyContainer, Dictionary<string, object>, object> factory)
|
||||
{
|
||||
if (factory == null)
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
_factory = new WeakReference(factory);
|
||||
|
||||
_registerType = registerType;
|
||||
}
|
||||
|
||||
public override bool AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => _registerType;
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!(_factory.Target is Func<DependencyContainer, Dictionary<string, object>, object> factory))
|
||||
throw new DependencyContainerWeakReferenceException(_registerType);
|
||||
|
||||
return new DelegateFactory(_registerType, factory);
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => this;
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
if (!(_factory.Target is Func<DependencyContainer, Dictionary<string, object>, object> factory))
|
||||
throw new DependencyContainerWeakReferenceException(_registerType);
|
||||
|
||||
try
|
||||
{
|
||||
return factory.Invoke(container, options.ConstructorParameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(_registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The singleton variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">singleton.</exception>
|
||||
public virtual ObjectFactoryBase SingletonVariant => throw new DependencyContainerRegistrationException(this.GetType(), "singleton");
|
||||
|
||||
/// <summary>
|
||||
/// Stores an particular instance to return for a type.
|
||||
/// Gets the multi instance variant.
|
||||
/// </summary>
|
||||
internal class InstanceFactory : ObjectFactoryBase, IDisposable
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly object _instance;
|
||||
|
||||
public InstanceFactory(Type registerType, Type registerImplementation, object instance)
|
||||
{
|
||||
if (!DependencyContainer.IsValidAssignment(registerType, registerImplementation))
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, "InstanceFactory", true);
|
||||
|
||||
_registerType = registerType;
|
||||
_registerImplementation = registerImplementation;
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public override bool AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => _registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant =>
|
||||
new MultiInstanceFactory(_registerType, _registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant =>
|
||||
new WeakInstanceFactory(_registerType, _registerImplementation, _instance);
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant => this;
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var disposable = _instance as IDisposable;
|
||||
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The multi instance variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">multi-instance.</exception>
|
||||
public virtual ObjectFactoryBase MultiInstanceVariant => throw new DependencyContainerRegistrationException(this.GetType(), "multi-instance");
|
||||
|
||||
/// <summary>
|
||||
/// Stores the instance with a weak reference.
|
||||
/// Gets the strong reference variant.
|
||||
/// </summary>
|
||||
internal class WeakInstanceFactory : ObjectFactoryBase, IDisposable
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly WeakReference _instance;
|
||||
|
||||
public WeakInstanceFactory(Type registerType, Type registerImplementation, object instance)
|
||||
{
|
||||
if (!DependencyContainer.IsValidAssignment(registerType, registerImplementation))
|
||||
{
|
||||
throw new DependencyContainerRegistrationException(
|
||||
registerImplementation,
|
||||
"WeakInstanceFactory",
|
||||
true);
|
||||
}
|
||||
|
||||
_registerType = registerType;
|
||||
_registerImplementation = registerImplementation;
|
||||
_instance = new WeakReference(instance);
|
||||
}
|
||||
|
||||
public override Type CreatesType => _registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant =>
|
||||
new MultiInstanceFactory(_registerType, _registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => this;
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant
|
||||
{
|
||||
get
|
||||
{
|
||||
var instance = _instance.Target;
|
||||
|
||||
if (instance == null)
|
||||
throw new DependencyContainerWeakReferenceException(_registerType);
|
||||
|
||||
return new InstanceFactory(_registerType, _registerImplementation, instance);
|
||||
}
|
||||
}
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
var instance = _instance.Target;
|
||||
|
||||
if (instance == null)
|
||||
throw new DependencyContainerWeakReferenceException(_registerType);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void Dispose() => (_instance.Target as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// The strong reference variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">strong reference.</exception>
|
||||
public virtual ObjectFactoryBase StrongReferenceVariant => throw new DependencyContainerRegistrationException(this.GetType(), "strong reference");
|
||||
|
||||
/// <summary>
|
||||
/// A factory that lazy instantiates a type and always returns the same instance.
|
||||
/// Gets the weak reference variant.
|
||||
/// </summary>
|
||||
internal class SingletonFactory : ObjectFactoryBase, IDisposable
|
||||
{
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly object _singletonLock = new object();
|
||||
private object _current;
|
||||
|
||||
public SingletonFactory(Type registerType, Type registerImplementation)
|
||||
{
|
||||
if (registerImplementation.IsAbstract || registerImplementation.IsInterface)
|
||||
{
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, nameof(SingletonFactory), true);
|
||||
}
|
||||
|
||||
if (!DependencyContainer.IsValidAssignment(registerType, registerImplementation))
|
||||
{
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, nameof(SingletonFactory), true);
|
||||
}
|
||||
|
||||
_registerType = registerType;
|
||||
_registerImplementation = registerImplementation;
|
||||
}
|
||||
|
||||
public override Type CreatesType => _registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase SingletonVariant => this;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant =>
|
||||
new MultiInstanceFactory(_registerType, _registerImplementation);
|
||||
|
||||
public override object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options)
|
||||
{
|
||||
if (options.ConstructorParameters.Count != 0)
|
||||
throw new ArgumentException("Cannot specify parameters for singleton types");
|
||||
|
||||
lock (_singletonLock)
|
||||
{
|
||||
if (_current == null)
|
||||
_current = container.RegisteredTypes.ConstructType(_registerImplementation, Constructor, options);
|
||||
}
|
||||
|
||||
return _current;
|
||||
}
|
||||
|
||||
public override ObjectFactoryBase GetFactoryForChildContainer(
|
||||
Type type,
|
||||
DependencyContainer parent,
|
||||
DependencyContainer child)
|
||||
{
|
||||
// We make sure that the singleton is constructed before the child container takes the factory.
|
||||
// Otherwise the results would vary depending on whether or not the parent container had resolved
|
||||
// the type before the child container does.
|
||||
GetObject(type, parent, DependencyContainerResolveOptions.Default);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Dispose() => (_current as IDisposable)?.Dispose();
|
||||
}
|
||||
/// <value>
|
||||
/// The weak reference variant.
|
||||
/// </value>
|
||||
/// <exception cref="DependencyContainerRegistrationException">weak reference.</exception>
|
||||
public virtual ObjectFactoryBase WeakReferenceVariant => throw new DependencyContainerRegistrationException(this.GetType(), "weak reference");
|
||||
|
||||
/// <summary>
|
||||
/// Create the type.
|
||||
/// </summary>
|
||||
/// <param name="requestedType">Type user requested to be resolved.</param>
|
||||
/// <param name="container">Container that requested the creation.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns> Instance of type. </returns>
|
||||
public abstract Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the factory for child container.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="child">The child.</param>
|
||||
/// <returns></returns>
|
||||
public virtual ObjectFactoryBase GetFactoryForChildContainer(Type type, DependencyContainer parent, DependencyContainer child) => this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// IObjectFactory that creates new instances of types for each resolution.
|
||||
/// </summary>
|
||||
internal class MultiInstanceFactory : ObjectFactoryBase {
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
|
||||
public MultiInstanceFactory(Type registerType, Type registerImplementation) {
|
||||
if(registerImplementation.IsAbstract || registerImplementation.IsInterface) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, "MultiInstanceFactory", true);
|
||||
}
|
||||
|
||||
if(!DependencyContainer.IsValidAssignment(registerType, registerImplementation)) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, "MultiInstanceFactory", true);
|
||||
}
|
||||
|
||||
this._registerType = registerType;
|
||||
this._registerImplementation = registerImplementation;
|
||||
}
|
||||
|
||||
public override Type CreatesType => this._registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase SingletonVariant =>
|
||||
new SingletonFactory(this._registerType, this._registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant => this;
|
||||
|
||||
public override Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options) {
|
||||
try {
|
||||
return container.RegisteredTypes.ConstructType(this._registerImplementation, this.Constructor, options);
|
||||
} catch(DependencyContainerResolutionException ex) {
|
||||
throw new DependencyContainerResolutionException(this._registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// IObjectFactory that invokes a specified delegate to construct the object.
|
||||
/// </summary>
|
||||
internal class DelegateFactory : ObjectFactoryBase {
|
||||
private readonly Type _registerType;
|
||||
|
||||
private readonly Func<DependencyContainer, Dictionary<String, Object>, Object> _factory;
|
||||
|
||||
public DelegateFactory(
|
||||
Type registerType,
|
||||
Func<DependencyContainer, Dictionary<String, Object>, Object> factory) {
|
||||
this._factory = factory ?? throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
this._registerType = registerType;
|
||||
}
|
||||
|
||||
public override Boolean AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => this._registerType;
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => new WeakDelegateFactory(this._registerType, this._factory);
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant => this;
|
||||
|
||||
public override Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options) {
|
||||
try {
|
||||
return this._factory.Invoke(container, options.ConstructorParameters);
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(this._registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// IObjectFactory that invokes a specified delegate to construct the object
|
||||
/// Holds the delegate using a weak reference.
|
||||
/// </summary>
|
||||
internal class WeakDelegateFactory : ObjectFactoryBase {
|
||||
private readonly Type _registerType;
|
||||
|
||||
private readonly WeakReference _factory;
|
||||
|
||||
public WeakDelegateFactory(Type registerType, Func<DependencyContainer, Dictionary<String, Object>, Object> factory) {
|
||||
if(factory == null) {
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
this._factory = new WeakReference(factory);
|
||||
|
||||
this._registerType = registerType;
|
||||
}
|
||||
|
||||
public override Boolean AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => this._registerType;
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant {
|
||||
get {
|
||||
if(!(this._factory.Target is Func<DependencyContainer, Dictionary<global::System.String, global::System.Object>, global::System.Object> factory)) {
|
||||
throw new DependencyContainerWeakReferenceException(this._registerType);
|
||||
}
|
||||
|
||||
return new DelegateFactory(this._registerType, factory);
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => this;
|
||||
|
||||
public override Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options) {
|
||||
if(!(this._factory.Target is Func<DependencyContainer, Dictionary<global::System.String, global::System.Object>, global::System.Object> factory)) {
|
||||
throw new DependencyContainerWeakReferenceException(this._registerType);
|
||||
}
|
||||
|
||||
try {
|
||||
return factory.Invoke(container, options.ConstructorParameters);
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(this._registerType, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores an particular instance to return for a type.
|
||||
/// </summary>
|
||||
internal class InstanceFactory : ObjectFactoryBase, IDisposable {
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly Object _instance;
|
||||
|
||||
public InstanceFactory(Type registerType, Type registerImplementation, Object instance) {
|
||||
if(!DependencyContainer.IsValidAssignment(registerType, registerImplementation)) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, "InstanceFactory", true);
|
||||
}
|
||||
|
||||
this._registerType = registerType;
|
||||
this._registerImplementation = registerImplementation;
|
||||
this._instance = instance;
|
||||
}
|
||||
|
||||
public override Boolean AssumeConstruction => true;
|
||||
|
||||
public override Type CreatesType => this._registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this._registerType, this._registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => new WeakInstanceFactory(this._registerType, this._registerImplementation, this._instance);
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant => this;
|
||||
|
||||
public override Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options) => this._instance;
|
||||
|
||||
public void Dispose() {
|
||||
IDisposable disposable = this._instance as IDisposable;
|
||||
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the instance with a weak reference.
|
||||
/// </summary>
|
||||
internal class WeakInstanceFactory : ObjectFactoryBase, IDisposable {
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly WeakReference _instance;
|
||||
|
||||
public WeakInstanceFactory(Type registerType, Type registerImplementation, Object instance) {
|
||||
if(!DependencyContainer.IsValidAssignment(registerType, registerImplementation)) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, "WeakInstanceFactory", true);
|
||||
}
|
||||
|
||||
this._registerType = registerType;
|
||||
this._registerImplementation = registerImplementation;
|
||||
this._instance = new WeakReference(instance);
|
||||
}
|
||||
|
||||
public override Type CreatesType => this._registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this._registerType, this._registerImplementation);
|
||||
|
||||
public override ObjectFactoryBase WeakReferenceVariant => this;
|
||||
|
||||
public override ObjectFactoryBase StrongReferenceVariant {
|
||||
get {
|
||||
Object instance = this._instance.Target;
|
||||
|
||||
if(instance == null) {
|
||||
throw new DependencyContainerWeakReferenceException(this._registerType);
|
||||
}
|
||||
|
||||
return new InstanceFactory(this._registerType, this._registerImplementation, instance);
|
||||
}
|
||||
}
|
||||
|
||||
public override Object GetObject(Type requestedType, DependencyContainer container, DependencyContainerResolveOptions options) {
|
||||
Object instance = this._instance.Target;
|
||||
|
||||
if(instance == null) {
|
||||
throw new DependencyContainerWeakReferenceException(this._registerType);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void Dispose() => (this._instance.Target as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A factory that lazy instantiates a type and always returns the same instance.
|
||||
/// </summary>
|
||||
internal class SingletonFactory : ObjectFactoryBase, IDisposable {
|
||||
private readonly Type _registerType;
|
||||
private readonly Type _registerImplementation;
|
||||
private readonly Object _singletonLock = new Object();
|
||||
private Object _current;
|
||||
|
||||
public SingletonFactory(Type registerType, Type registerImplementation) {
|
||||
if(registerImplementation.IsAbstract || registerImplementation.IsInterface) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, nameof(SingletonFactory), true);
|
||||
}
|
||||
|
||||
if(!DependencyContainer.IsValidAssignment(registerType, registerImplementation)) {
|
||||
throw new DependencyContainerRegistrationException(registerImplementation, nameof(SingletonFactory), true);
|
||||
}
|
||||
|
||||
this._registerType = registerType;
|
||||
this._registerImplementation = registerImplementation;
|
||||
}
|
||||
|
||||
public override Type CreatesType => this._registerImplementation;
|
||||
|
||||
public override ObjectFactoryBase SingletonVariant => this;
|
||||
|
||||
public override ObjectFactoryBase MultiInstanceVariant =>
|
||||
new MultiInstanceFactory(this._registerType, this._registerImplementation);
|
||||
|
||||
public override Object GetObject(
|
||||
Type requestedType,
|
||||
DependencyContainer container,
|
||||
DependencyContainerResolveOptions options) {
|
||||
if(options.ConstructorParameters.Count != 0) {
|
||||
throw new ArgumentException("Cannot specify parameters for singleton types");
|
||||
}
|
||||
|
||||
lock(this._singletonLock) {
|
||||
if(this._current == null) {
|
||||
this._current = container.RegisteredTypes.ConstructType(this._registerImplementation, this.Constructor, options);
|
||||
}
|
||||
}
|
||||
|
||||
return this._current;
|
||||
}
|
||||
|
||||
public override ObjectFactoryBase GetFactoryForChildContainer(
|
||||
Type type,
|
||||
DependencyContainer parent,
|
||||
DependencyContainer child) {
|
||||
// We make sure that the singleton is constructed before the child container takes the factory.
|
||||
// Otherwise the results would vary depending on whether or not the parent container had resolved
|
||||
// the type before the child container does.
|
||||
_ = this.GetObject(type, parent, DependencyContainerResolveOptions.Default);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Dispose() => (this._current as IDisposable)?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +1,119 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Registration options for "fluent" API.
|
||||
/// </summary>
|
||||
public sealed class RegisterOptions {
|
||||
private readonly TypesConcurrentDictionary _registeredTypes;
|
||||
private readonly DependencyContainer.TypeRegistration _registration;
|
||||
|
||||
/// <summary>
|
||||
/// Registration options for "fluent" API.
|
||||
/// Initializes a new instance of the <see cref="RegisterOptions" /> class.
|
||||
/// </summary>
|
||||
public sealed class RegisterOptions
|
||||
{
|
||||
private readonly TypesConcurrentDictionary _registeredTypes;
|
||||
private readonly DependencyContainer.TypeRegistration _registration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegisterOptions" /> class.
|
||||
/// </summary>
|
||||
/// <param name="registeredTypes">The registered types.</param>
|
||||
/// <param name="registration">The registration.</param>
|
||||
public RegisterOptions(TypesConcurrentDictionary registeredTypes, DependencyContainer.TypeRegistration registration)
|
||||
{
|
||||
_registeredTypes = registeredTypes;
|
||||
_registration = registration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration a singleton (single instance) if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions AsSingleton()
|
||||
{
|
||||
var currentFactory = _registeredTypes.GetCurrentFactory(_registration);
|
||||
|
||||
if (currentFactory == null)
|
||||
throw new DependencyContainerRegistrationException(_registration.Type, "singleton");
|
||||
|
||||
return _registeredTypes.AddUpdateRegistration(_registration, currentFactory.SingletonVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration multi-instance if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions AsMultiInstance()
|
||||
{
|
||||
var currentFactory = _registeredTypes.GetCurrentFactory(_registration);
|
||||
|
||||
if (currentFactory == null)
|
||||
throw new DependencyContainerRegistrationException(_registration.Type, "multi-instance");
|
||||
|
||||
return _registeredTypes.AddUpdateRegistration(_registration, currentFactory.MultiInstanceVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration hold a weak reference if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions WithWeakReference()
|
||||
{
|
||||
var currentFactory = _registeredTypes.GetCurrentFactory(_registration);
|
||||
|
||||
if (currentFactory == null)
|
||||
throw new DependencyContainerRegistrationException(_registration.Type, "weak reference");
|
||||
|
||||
return _registeredTypes.AddUpdateRegistration(_registration, currentFactory.WeakReferenceVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration hold a strong reference if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions WithStrongReference()
|
||||
{
|
||||
var currentFactory = _registeredTypes.GetCurrentFactory(_registration);
|
||||
|
||||
if (currentFactory == null)
|
||||
throw new DependencyContainerRegistrationException(_registration.Type, "strong reference");
|
||||
|
||||
return _registeredTypes.AddUpdateRegistration(_registration, currentFactory.StrongReferenceVariant);
|
||||
}
|
||||
}
|
||||
|
||||
/// <param name="registeredTypes">The registered types.</param>
|
||||
/// <param name="registration">The registration.</param>
|
||||
public RegisterOptions(TypesConcurrentDictionary registeredTypes, DependencyContainer.TypeRegistration registration) {
|
||||
this._registeredTypes = registeredTypes;
|
||||
this._registration = registration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registration options for "fluent" API when registering multiple implementations.
|
||||
/// Make registration a singleton (single instance) if possible.
|
||||
/// </summary>
|
||||
public sealed class MultiRegisterOptions
|
||||
{
|
||||
private IEnumerable<RegisterOptions> _registerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MultiRegisterOptions"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registerOptions">The register options.</param>
|
||||
public MultiRegisterOptions(IEnumerable<RegisterOptions> registerOptions)
|
||||
{
|
||||
_registerOptions = registerOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration a singleton (single instance) if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration multi-instance for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic Constraint Registration Exception.</exception>
|
||||
public MultiRegisterOptions AsSingleton()
|
||||
{
|
||||
_registerOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration multi-instance if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration multi-instance for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic Constraint Registration Exception.</exception>
|
||||
public MultiRegisterOptions AsMultiInstance()
|
||||
{
|
||||
_registerOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance());
|
||||
return this;
|
||||
}
|
||||
|
||||
private IEnumerable<RegisterOptions> ExecuteOnAllRegisterOptions(
|
||||
Func<RegisterOptions, RegisterOptions> action)
|
||||
{
|
||||
return _registerOptions.Select(action).ToList();
|
||||
}
|
||||
}
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions AsSingleton() {
|
||||
ObjectFactoryBase currentFactory = this._registeredTypes.GetCurrentFactory(this._registration);
|
||||
|
||||
if(currentFactory == null) {
|
||||
throw new DependencyContainerRegistrationException(this._registration.Type, "singleton");
|
||||
}
|
||||
|
||||
return this._registeredTypes.AddUpdateRegistration(this._registration, currentFactory.SingletonVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration multi-instance if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions AsMultiInstance() {
|
||||
ObjectFactoryBase currentFactory = this._registeredTypes.GetCurrentFactory(this._registration);
|
||||
|
||||
if(currentFactory == null) {
|
||||
throw new DependencyContainerRegistrationException(this._registration.Type, "multi-instance");
|
||||
}
|
||||
|
||||
return this._registeredTypes.AddUpdateRegistration(this._registration, currentFactory.MultiInstanceVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration hold a weak reference if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions WithWeakReference() {
|
||||
ObjectFactoryBase currentFactory = this._registeredTypes.GetCurrentFactory(this._registration);
|
||||
|
||||
if(currentFactory == null) {
|
||||
throw new DependencyContainerRegistrationException(this._registration.Type, "weak reference");
|
||||
}
|
||||
|
||||
return this._registeredTypes.AddUpdateRegistration(this._registration, currentFactory.WeakReferenceVariant);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration hold a strong reference if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration options for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic constraint registration exception.</exception>
|
||||
public RegisterOptions WithStrongReference() {
|
||||
ObjectFactoryBase currentFactory = this._registeredTypes.GetCurrentFactory(this._registration);
|
||||
|
||||
if(currentFactory == null) {
|
||||
throw new DependencyContainerRegistrationException(this._registration.Type, "strong reference");
|
||||
}
|
||||
|
||||
return this._registeredTypes.AddUpdateRegistration(this._registration, currentFactory.StrongReferenceVariant);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registration options for "fluent" API when registering multiple implementations.
|
||||
/// </summary>
|
||||
public sealed class MultiRegisterOptions {
|
||||
private IEnumerable<RegisterOptions> _registerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MultiRegisterOptions"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registerOptions">The register options.</param>
|
||||
public MultiRegisterOptions(IEnumerable<RegisterOptions> registerOptions) => this._registerOptions = registerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Make registration a singleton (single instance) if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration multi-instance for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic Constraint Registration Exception.</exception>
|
||||
public MultiRegisterOptions AsSingleton() {
|
||||
this._registerOptions = this.ExecuteOnAllRegisterOptions(ro => ro.AsSingleton());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make registration multi-instance if possible.
|
||||
/// </summary>
|
||||
/// <returns>A registration multi-instance for fluent API.</returns>
|
||||
/// <exception cref="DependencyContainerRegistrationException">Generic Constraint Registration Exception.</exception>
|
||||
public MultiRegisterOptions AsMultiInstance() {
|
||||
this._registerOptions = this.ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance());
|
||||
return this;
|
||||
}
|
||||
|
||||
private IEnumerable<RegisterOptions> ExecuteOnAllRegisterOptions(
|
||||
Func<RegisterOptions, RegisterOptions> action) => this._registerOptions.Select(action).ToList();
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,61 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
|
||||
public partial class DependencyContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Type Registration within the IoC Container.
|
||||
/// </summary>
|
||||
public sealed class TypeRegistration
|
||||
{
|
||||
private readonly int _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeRegistration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
public TypeRegistration(Type type, string name = null)
|
||||
{
|
||||
Type = type;
|
||||
Name = name ?? string.Empty;
|
||||
|
||||
_hashCode = string.Concat(Type.FullName, "|", Name).GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The type.
|
||||
/// </value>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name.
|
||||
/// </value>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is TypeRegistration typeRegistration) || typeRegistration.Type != Type)
|
||||
return false;
|
||||
|
||||
return string.Compare(Name, typeRegistration.Name, StringComparison.Ordinal) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode() => _hashCode;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
public partial class DependencyContainer {
|
||||
/// <summary>
|
||||
/// Represents a Type Registration within the IoC Container.
|
||||
/// </summary>
|
||||
public sealed class TypeRegistration {
|
||||
private readonly Int32 _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeRegistration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
public TypeRegistration(Type type, String name = null) {
|
||||
this.Type = type;
|
||||
this.Name = name ?? String.Empty;
|
||||
|
||||
this._hashCode = String.Concat(this.Type.FullName, "|", this.Name).GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The type.
|
||||
/// </value>
|
||||
public Type Type {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name.
|
||||
/// </value>
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override Boolean Equals(Object obj) => !(obj is TypeRegistration typeRegistration) || typeRegistration.Type != this.Type ? false : String.Compare(this.Name, typeRegistration.Name, StringComparison.Ordinal) == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||
/// </returns>
|
||||
public override Int32 GetHashCode() => this._hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,351 +1,265 @@
|
||||
namespace Swan.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Swan.DependencyInjection {
|
||||
/// <summary>
|
||||
/// Represents a Concurrent Dictionary for TypeRegistration.
|
||||
/// </summary>
|
||||
public class TypesConcurrentDictionary : ConcurrentDictionary<DependencyContainer.TypeRegistration, ObjectFactoryBase> {
|
||||
private static readonly ConcurrentDictionary<ConstructorInfo, ObjectConstructor> ObjectConstructorCache = new ConcurrentDictionary<ConstructorInfo, ObjectConstructor>();
|
||||
|
||||
private readonly DependencyContainer _dependencyContainer;
|
||||
|
||||
internal TypesConcurrentDictionary(DependencyContainer dependencyContainer) => this._dependencyContainer = dependencyContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Concurrent Dictionary for TypeRegistration.
|
||||
/// Represents a delegate to build an object with the parameters.
|
||||
/// </summary>
|
||||
public class TypesConcurrentDictionary : ConcurrentDictionary<DependencyContainer.TypeRegistration, ObjectFactoryBase>
|
||||
{
|
||||
private static readonly ConcurrentDictionary<ConstructorInfo, ObjectConstructor> ObjectConstructorCache =
|
||||
new ConcurrentDictionary<ConstructorInfo, ObjectConstructor>();
|
||||
|
||||
private readonly DependencyContainer _dependencyContainer;
|
||||
|
||||
internal TypesConcurrentDictionary(DependencyContainer dependencyContainer)
|
||||
{
|
||||
_dependencyContainer = dependencyContainer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a delegate to build an object with the parameters.
|
||||
/// </summary>
|
||||
/// <param name="parameters">The parameters.</param>
|
||||
/// <returns>The built object.</returns>
|
||||
public delegate object ObjectConstructor(params object[] parameters);
|
||||
|
||||
internal IEnumerable<object> Resolve(Type resolveType, bool includeUnnamed)
|
||||
{
|
||||
var registrations = Keys.Where(tr => tr.Type == resolveType)
|
||||
.Concat(GetParentRegistrationsForType(resolveType)).Distinct();
|
||||
|
||||
if (!includeUnnamed)
|
||||
registrations = registrations.Where(tr => !string.IsNullOrEmpty(tr.Name));
|
||||
|
||||
return registrations.Select(registration =>
|
||||
ResolveInternal(registration, DependencyContainerResolveOptions.Default));
|
||||
}
|
||||
|
||||
internal ObjectFactoryBase GetCurrentFactory(DependencyContainer.TypeRegistration registration)
|
||||
{
|
||||
TryGetValue(registration, out var current);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
internal RegisterOptions Register(Type registerType, string name, ObjectFactoryBase factory)
|
||||
=> AddUpdateRegistration(new DependencyContainer.TypeRegistration(registerType, name), factory);
|
||||
|
||||
internal RegisterOptions AddUpdateRegistration(DependencyContainer.TypeRegistration typeRegistration, ObjectFactoryBase factory)
|
||||
{
|
||||
this[typeRegistration] = factory;
|
||||
|
||||
return new RegisterOptions(this, typeRegistration);
|
||||
}
|
||||
|
||||
internal bool RemoveRegistration(DependencyContainer.TypeRegistration typeRegistration)
|
||||
=> TryRemove(typeRegistration, out _);
|
||||
|
||||
internal object ResolveInternal(
|
||||
DependencyContainer.TypeRegistration registration,
|
||||
DependencyContainerResolveOptions? options = null)
|
||||
{
|
||||
if (options == null)
|
||||
options = DependencyContainerResolveOptions.Default;
|
||||
|
||||
// Attempt container resolution
|
||||
if (TryGetValue(registration, out var factory))
|
||||
{
|
||||
try
|
||||
{
|
||||
return factory.GetObject(registration.Type, _dependencyContainer, options);
|
||||
}
|
||||
catch (DependencyContainerResolutionException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get a factory from parent if we can
|
||||
var bubbledObjectFactory = GetParentObjectFactory(registration);
|
||||
if (bubbledObjectFactory != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return bubbledObjectFactory.GetObject(registration.Type, _dependencyContainer, options);
|
||||
}
|
||||
catch (DependencyContainerResolutionException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if requesting named resolution and settings set to fail if unresolved
|
||||
if (!string.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction ==
|
||||
DependencyContainerNamedResolutionFailureAction.Fail)
|
||||
throw new DependencyContainerResolutionException(registration.Type);
|
||||
|
||||
// Attempted unnamed fallback container resolution if relevant and requested
|
||||
if (!string.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction ==
|
||||
DependencyContainerNamedResolutionFailureAction.AttemptUnnamedResolution)
|
||||
{
|
||||
if (TryGetValue(new DependencyContainer.TypeRegistration(registration.Type, string.Empty), out factory))
|
||||
{
|
||||
try
|
||||
{
|
||||
return factory.GetObject(registration.Type, _dependencyContainer, options);
|
||||
}
|
||||
catch (DependencyContainerResolutionException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt unregistered construction if possible and requested
|
||||
var isValid = (options.UnregisteredResolutionAction ==
|
||||
DependencyContainerUnregisteredResolutionAction.AttemptResolve) ||
|
||||
(registration.Type.IsGenericType && options.UnregisteredResolutionAction ==
|
||||
DependencyContainerUnregisteredResolutionAction.GenericsOnly);
|
||||
|
||||
return isValid && !registration.Type.IsAbstract && !registration.Type.IsInterface
|
||||
? ConstructType(registration.Type, null, options)
|
||||
: throw new DependencyContainerResolutionException(registration.Type);
|
||||
}
|
||||
|
||||
internal bool CanResolve(
|
||||
DependencyContainer.TypeRegistration registration,
|
||||
DependencyContainerResolveOptions? options = null)
|
||||
{
|
||||
if (options == null)
|
||||
options = DependencyContainerResolveOptions.Default;
|
||||
|
||||
var checkType = registration.Type;
|
||||
var name = registration.Name;
|
||||
|
||||
if (TryGetValue(new DependencyContainer.TypeRegistration(checkType, name), out var factory))
|
||||
{
|
||||
if (factory.AssumeConstruction)
|
||||
return true;
|
||||
|
||||
if (factory.Constructor == null)
|
||||
return GetBestConstructor(factory.CreatesType, options) != null;
|
||||
|
||||
return CanConstruct(factory.Constructor, options);
|
||||
}
|
||||
|
||||
// Fail if requesting named resolution and settings set to fail if unresolved
|
||||
// Or bubble up if we have a parent
|
||||
if (!string.IsNullOrEmpty(name) && options.NamedResolutionFailureAction ==
|
||||
DependencyContainerNamedResolutionFailureAction.Fail)
|
||||
return _dependencyContainer.Parent?.RegisteredTypes.CanResolve(registration, options.Clone()) ?? false;
|
||||
|
||||
// Attempted unnamed fallback container resolution if relevant and requested
|
||||
if (!string.IsNullOrEmpty(name) && options.NamedResolutionFailureAction ==
|
||||
DependencyContainerNamedResolutionFailureAction.AttemptUnnamedResolution)
|
||||
{
|
||||
if (TryGetValue(new DependencyContainer.TypeRegistration(checkType), out factory))
|
||||
{
|
||||
if (factory.AssumeConstruction)
|
||||
return true;
|
||||
|
||||
return GetBestConstructor(factory.CreatesType, options) != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if type is an automatic lazy factory request or an IEnumerable<ResolveType>
|
||||
if (IsAutomaticLazyFactoryRequest(checkType) || registration.Type.IsIEnumerable())
|
||||
return true;
|
||||
|
||||
// Attempt unregistered construction if possible and requested
|
||||
// If we cant', bubble if we have a parent
|
||||
if ((options.UnregisteredResolutionAction ==
|
||||
DependencyContainerUnregisteredResolutionAction.AttemptResolve) ||
|
||||
(checkType.IsGenericType && options.UnregisteredResolutionAction ==
|
||||
DependencyContainerUnregisteredResolutionAction.GenericsOnly))
|
||||
{
|
||||
return (GetBestConstructor(checkType, options) != null) ||
|
||||
(_dependencyContainer.Parent?.RegisteredTypes.CanResolve(registration, options.Clone()) ?? false);
|
||||
}
|
||||
|
||||
// Bubble resolution up the container tree if we have a parent
|
||||
return _dependencyContainer.Parent != null && _dependencyContainer.Parent.RegisteredTypes.CanResolve(registration, options.Clone());
|
||||
}
|
||||
|
||||
internal object ConstructType(
|
||||
Type implementationType,
|
||||
ConstructorInfo constructor,
|
||||
DependencyContainerResolveOptions? options = null)
|
||||
{
|
||||
var typeToConstruct = implementationType;
|
||||
|
||||
if (constructor == null)
|
||||
{
|
||||
// Try and get the best constructor that we can construct
|
||||
// if we can't construct any then get the constructor
|
||||
// with the least number of parameters so we can throw a meaningful
|
||||
// resolve exception
|
||||
constructor = GetBestConstructor(typeToConstruct, options) ??
|
||||
GetTypeConstructors(typeToConstruct).LastOrDefault();
|
||||
}
|
||||
|
||||
if (constructor == null)
|
||||
throw new DependencyContainerResolutionException(typeToConstruct);
|
||||
|
||||
var ctorParams = constructor.GetParameters();
|
||||
var args = new object?[ctorParams.Length];
|
||||
|
||||
for (var parameterIndex = 0; parameterIndex < ctorParams.Length; parameterIndex++)
|
||||
{
|
||||
var currentParam = ctorParams[parameterIndex];
|
||||
|
||||
try
|
||||
{
|
||||
args[parameterIndex] = options?.ConstructorParameters.GetValueOrDefault(currentParam.Name, ResolveInternal(new DependencyContainer.TypeRegistration(currentParam.ParameterType), options.Clone()));
|
||||
}
|
||||
catch (DependencyContainerResolutionException ex)
|
||||
{
|
||||
// If a constructor parameter can't be resolved
|
||||
// it will throw, so wrap it and throw that this can't
|
||||
// be resolved.
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return CreateObjectConstructionDelegateWithCache(constructor).Invoke(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static ObjectConstructor CreateObjectConstructionDelegateWithCache(ConstructorInfo constructor)
|
||||
{
|
||||
if (ObjectConstructorCache.TryGetValue(constructor, out var objectConstructor))
|
||||
return objectConstructor;
|
||||
|
||||
// We could lock the cache here, but there's no real side
|
||||
// effect to two threads creating the same ObjectConstructor
|
||||
// at the same time, compared to the cost of a lock for
|
||||
// every creation.
|
||||
var constructorParams = constructor.GetParameters();
|
||||
var lambdaParams = Expression.Parameter(typeof(object[]), "parameters");
|
||||
var newParams = new Expression[constructorParams.Length];
|
||||
|
||||
for (var i = 0; i < constructorParams.Length; i++)
|
||||
{
|
||||
var paramsParameter = Expression.ArrayIndex(lambdaParams, Expression.Constant(i));
|
||||
|
||||
newParams[i] = Expression.Convert(paramsParameter, constructorParams[i].ParameterType);
|
||||
}
|
||||
|
||||
var newExpression = Expression.New(constructor, newParams);
|
||||
|
||||
var constructionLambda = Expression.Lambda(typeof(ObjectConstructor), newExpression, lambdaParams);
|
||||
|
||||
objectConstructor = (ObjectConstructor)constructionLambda.Compile();
|
||||
|
||||
ObjectConstructorCache[constructor] = objectConstructor;
|
||||
return objectConstructor;
|
||||
}
|
||||
|
||||
private static IEnumerable<ConstructorInfo> GetTypeConstructors(Type type)
|
||||
=> type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Length);
|
||||
|
||||
private static bool IsAutomaticLazyFactoryRequest(Type type)
|
||||
{
|
||||
if (!type.IsGenericType)
|
||||
return false;
|
||||
|
||||
var genericType = type.GetGenericTypeDefinition();
|
||||
|
||||
// Just a func
|
||||
if (genericType == typeof(Func<>))
|
||||
return true;
|
||||
|
||||
// 2 parameter func with string as first parameter (name)
|
||||
if (genericType == typeof(Func<,>) && type.GetGenericArguments()[0] == typeof(string))
|
||||
return true;
|
||||
|
||||
// 3 parameter func with string as first parameter (name) and IDictionary<string, object> as second (parameters)
|
||||
return genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) &&
|
||||
type.GetGenericArguments()[1] == typeof(IDictionary<string, object>);
|
||||
}
|
||||
|
||||
private ObjectFactoryBase? GetParentObjectFactory(DependencyContainer.TypeRegistration registration)
|
||||
{
|
||||
if (_dependencyContainer.Parent == null)
|
||||
return null;
|
||||
|
||||
return _dependencyContainer.Parent.RegisteredTypes.TryGetValue(registration, out var factory)
|
||||
? factory.GetFactoryForChildContainer(registration.Type, _dependencyContainer.Parent, _dependencyContainer)
|
||||
: _dependencyContainer.Parent.RegisteredTypes.GetParentObjectFactory(registration);
|
||||
}
|
||||
|
||||
private ConstructorInfo? GetBestConstructor(
|
||||
Type type,
|
||||
DependencyContainerResolveOptions options)
|
||||
=> type.IsValueType ? null : GetTypeConstructors(type).FirstOrDefault(ctor => CanConstruct(ctor, options));
|
||||
|
||||
private bool CanConstruct(
|
||||
MethodBase ctor,
|
||||
DependencyContainerResolveOptions? options)
|
||||
{
|
||||
foreach (var parameter in ctor.GetParameters())
|
||||
{
|
||||
if (string.IsNullOrEmpty(parameter.Name))
|
||||
return false;
|
||||
|
||||
var isParameterOverload = options.ConstructorParameters.ContainsKey(parameter.Name);
|
||||
|
||||
if (parameter.ParameterType.IsPrimitive && !isParameterOverload)
|
||||
return false;
|
||||
|
||||
if (!isParameterOverload &&
|
||||
!CanResolve(new DependencyContainer.TypeRegistration(parameter.ParameterType), options.Clone()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<DependencyContainer.TypeRegistration> GetParentRegistrationsForType(Type resolveType)
|
||||
=> _dependencyContainer.Parent == null
|
||||
? Array.Empty<DependencyContainer.TypeRegistration>()
|
||||
: _dependencyContainer.Parent.RegisteredTypes.Keys.Where(tr => tr.Type == resolveType).Concat(_dependencyContainer.Parent.RegisteredTypes.GetParentRegistrationsForType(resolveType));
|
||||
}
|
||||
/// <param name="parameters">The parameters.</param>
|
||||
/// <returns>The built object.</returns>
|
||||
public delegate Object ObjectConstructor(params Object?[] parameters);
|
||||
|
||||
internal IEnumerable<Object> Resolve(Type resolveType, Boolean includeUnnamed) {
|
||||
IEnumerable<DependencyContainer.TypeRegistration> registrations = this.Keys.Where(tr => tr.Type == resolveType).Concat(this.GetParentRegistrationsForType(resolveType)).Distinct();
|
||||
|
||||
if(!includeUnnamed) {
|
||||
registrations = registrations.Where(tr => !String.IsNullOrEmpty(tr.Name));
|
||||
}
|
||||
|
||||
return registrations.Select(registration => this.ResolveInternal(registration, DependencyContainerResolveOptions.Default));
|
||||
}
|
||||
|
||||
internal ObjectFactoryBase GetCurrentFactory(DependencyContainer.TypeRegistration registration) {
|
||||
_ = this.TryGetValue(registration, out ObjectFactoryBase? current);
|
||||
|
||||
return current!;
|
||||
}
|
||||
|
||||
internal RegisterOptions Register(Type registerType, String name, ObjectFactoryBase factory) => this.AddUpdateRegistration(new DependencyContainer.TypeRegistration(registerType, name), factory);
|
||||
|
||||
internal RegisterOptions AddUpdateRegistration(DependencyContainer.TypeRegistration typeRegistration, ObjectFactoryBase factory) {
|
||||
this[typeRegistration] = factory;
|
||||
|
||||
return new RegisterOptions(this, typeRegistration);
|
||||
}
|
||||
|
||||
internal Boolean RemoveRegistration(DependencyContainer.TypeRegistration typeRegistration) => this.TryRemove(typeRegistration, out _);
|
||||
|
||||
internal Object ResolveInternal(DependencyContainer.TypeRegistration registration, DependencyContainerResolveOptions? options = null) {
|
||||
if(options == null) {
|
||||
options = DependencyContainerResolveOptions.Default;
|
||||
}
|
||||
|
||||
// Attempt container resolution
|
||||
if(this.TryGetValue(registration, out ObjectFactoryBase? factory)) {
|
||||
try {
|
||||
return factory.GetObject(registration.Type, this._dependencyContainer, options);
|
||||
} catch(DependencyContainerResolutionException) {
|
||||
throw;
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get a factory from parent if we can
|
||||
ObjectFactoryBase? bubbledObjectFactory = this.GetParentObjectFactory(registration);
|
||||
if(bubbledObjectFactory != null) {
|
||||
try {
|
||||
return bubbledObjectFactory.GetObject(registration.Type, this._dependencyContainer, options);
|
||||
} catch(DependencyContainerResolutionException) {
|
||||
throw;
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if requesting named resolution and settings set to fail if unresolved
|
||||
if(!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == DependencyContainerNamedResolutionFailureAction.Fail) {
|
||||
throw new DependencyContainerResolutionException(registration.Type);
|
||||
}
|
||||
|
||||
// Attempted unnamed fallback container resolution if relevant and requested
|
||||
if(!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == DependencyContainerNamedResolutionFailureAction.AttemptUnnamedResolution) {
|
||||
if(this.TryGetValue(new DependencyContainer.TypeRegistration(registration.Type, String.Empty), out factory)) {
|
||||
try {
|
||||
return factory.GetObject(registration.Type, this._dependencyContainer, options);
|
||||
} catch(DependencyContainerResolutionException) {
|
||||
throw;
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(registration.Type, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt unregistered construction if possible and requested
|
||||
Boolean isValid = options.UnregisteredResolutionAction == DependencyContainerUnregisteredResolutionAction.AttemptResolve || registration.Type.IsGenericType && options.UnregisteredResolutionAction == DependencyContainerUnregisteredResolutionAction.GenericsOnly;
|
||||
|
||||
return isValid && !registration.Type.IsAbstract && !registration.Type.IsInterface ? this.ConstructType(registration.Type, null, options) : throw new DependencyContainerResolutionException(registration.Type);
|
||||
}
|
||||
|
||||
internal Boolean CanResolve(DependencyContainer.TypeRegistration registration, DependencyContainerResolveOptions? options = null) {
|
||||
if(options == null) {
|
||||
options = DependencyContainerResolveOptions.Default;
|
||||
}
|
||||
|
||||
Type checkType = registration.Type;
|
||||
String name = registration.Name;
|
||||
|
||||
if(this.TryGetValue(new DependencyContainer.TypeRegistration(checkType, name), out ObjectFactoryBase? factory)) {
|
||||
return factory.AssumeConstruction ? true : factory.Constructor == null ? this.GetBestConstructor(factory.CreatesType, options) != null : this.CanConstruct(factory.Constructor, options);
|
||||
}
|
||||
|
||||
// Fail if requesting named resolution and settings set to fail if unresolved
|
||||
// Or bubble up if we have a parent
|
||||
if(!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == DependencyContainerNamedResolutionFailureAction.Fail) {
|
||||
return this._dependencyContainer.Parent?.RegisteredTypes.CanResolve(registration, options.Clone()) ?? false;
|
||||
}
|
||||
|
||||
// Attempted unnamed fallback container resolution if relevant and requested
|
||||
if(!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == DependencyContainerNamedResolutionFailureAction.AttemptUnnamedResolution) {
|
||||
if(this.TryGetValue(new DependencyContainer.TypeRegistration(checkType), out factory)) {
|
||||
return factory.AssumeConstruction ? true : this.GetBestConstructor(factory.CreatesType, options) != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if type is an automatic lazy factory request or an IEnumerable<ResolveType>
|
||||
if(IsAutomaticLazyFactoryRequest(checkType) || registration.Type.IsIEnumerable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempt unregistered construction if possible and requested
|
||||
// If we cant', bubble if we have a parent
|
||||
if(options.UnregisteredResolutionAction == DependencyContainerUnregisteredResolutionAction.AttemptResolve || checkType.IsGenericType && options.UnregisteredResolutionAction == DependencyContainerUnregisteredResolutionAction.GenericsOnly) {
|
||||
return this.GetBestConstructor(checkType, options) != null || (this._dependencyContainer.Parent?.RegisteredTypes.CanResolve(registration, options.Clone()) ?? false);
|
||||
}
|
||||
|
||||
// Bubble resolution up the container tree if we have a parent
|
||||
return this._dependencyContainer.Parent != null && this._dependencyContainer.Parent.RegisteredTypes.CanResolve(registration, options.Clone());
|
||||
}
|
||||
|
||||
internal Object ConstructType(Type implementationType, ConstructorInfo? constructor, DependencyContainerResolveOptions? options = null) {
|
||||
Type typeToConstruct = implementationType;
|
||||
|
||||
if(constructor == null) {
|
||||
// Try and get the best constructor that we can construct
|
||||
// if we can't construct any then get the constructor
|
||||
// with the least number of parameters so we can throw a meaningful
|
||||
// resolve exception
|
||||
constructor = this.GetBestConstructor(typeToConstruct, options) ?? GetTypeConstructors(typeToConstruct).LastOrDefault();
|
||||
}
|
||||
|
||||
if(constructor == null) {
|
||||
throw new DependencyContainerResolutionException(typeToConstruct);
|
||||
}
|
||||
|
||||
ParameterInfo[] ctorParams = constructor.GetParameters();
|
||||
Object?[] args = new Object?[ctorParams.Length];
|
||||
|
||||
for(Int32 parameterIndex = 0; parameterIndex < ctorParams.Length; parameterIndex++) {
|
||||
ParameterInfo currentParam = ctorParams[parameterIndex];
|
||||
|
||||
try {
|
||||
args[parameterIndex] = options?.ConstructorParameters.GetValueOrDefault(currentParam.Name, this.ResolveInternal(new DependencyContainer.TypeRegistration(currentParam.ParameterType), options.Clone()));
|
||||
} catch(DependencyContainerResolutionException ex) {
|
||||
// If a constructor parameter can't be resolved
|
||||
// it will throw, so wrap it and throw that this can't
|
||||
// be resolved.
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return CreateObjectConstructionDelegateWithCache(constructor).Invoke(args);
|
||||
} catch(Exception ex) {
|
||||
throw new DependencyContainerResolutionException(typeToConstruct, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static ObjectConstructor CreateObjectConstructionDelegateWithCache(ConstructorInfo constructor) {
|
||||
if(ObjectConstructorCache.TryGetValue(constructor, out ObjectConstructor? objectConstructor)) {
|
||||
return objectConstructor;
|
||||
}
|
||||
|
||||
// We could lock the cache here, but there's no real side
|
||||
// effect to two threads creating the same ObjectConstructor
|
||||
// at the same time, compared to the cost of a lock for
|
||||
// every creation.
|
||||
ParameterInfo[] constructorParams = constructor.GetParameters();
|
||||
ParameterExpression lambdaParams = Expression.Parameter(typeof(Object[]), "parameters");
|
||||
Expression[] newParams = new Expression[constructorParams.Length];
|
||||
|
||||
for(Int32 i = 0; i < constructorParams.Length; i++) {
|
||||
BinaryExpression paramsParameter = Expression.ArrayIndex(lambdaParams, Expression.Constant(i));
|
||||
|
||||
newParams[i] = Expression.Convert(paramsParameter, constructorParams[i].ParameterType);
|
||||
}
|
||||
|
||||
NewExpression newExpression = Expression.New(constructor, newParams);
|
||||
|
||||
LambdaExpression constructionLambda = Expression.Lambda(typeof(ObjectConstructor), newExpression, lambdaParams);
|
||||
|
||||
objectConstructor = (ObjectConstructor)constructionLambda.Compile();
|
||||
|
||||
ObjectConstructorCache[constructor] = objectConstructor;
|
||||
return objectConstructor;
|
||||
}
|
||||
|
||||
private static IEnumerable<ConstructorInfo> GetTypeConstructors(Type type) => type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Length);
|
||||
|
||||
private static Boolean IsAutomaticLazyFactoryRequest(Type type) {
|
||||
if(!type.IsGenericType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type genericType = type.GetGenericTypeDefinition();
|
||||
|
||||
// Just a func
|
||||
if(genericType == typeof(Func<>)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2 parameter func with string as first parameter (name)
|
||||
if(genericType == typeof(Func<,>) && type.GetGenericArguments()[0] == typeof(String)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3 parameter func with string as first parameter (name) and IDictionary<string, object> as second (parameters)
|
||||
return genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(String) && type.GetGenericArguments()[1] == typeof(IDictionary<String, Object>);
|
||||
}
|
||||
|
||||
private ObjectFactoryBase? GetParentObjectFactory(DependencyContainer.TypeRegistration registration) => this._dependencyContainer.Parent == null
|
||||
? null
|
||||
: this._dependencyContainer.Parent.RegisteredTypes.TryGetValue(registration, out ObjectFactoryBase? factory) ? factory.GetFactoryForChildContainer(registration.Type, this._dependencyContainer.Parent, this._dependencyContainer) : this._dependencyContainer.Parent.RegisteredTypes.GetParentObjectFactory(registration);
|
||||
|
||||
private ConstructorInfo? GetBestConstructor(Type type, DependencyContainerResolveOptions? options) => type.IsValueType ? null : GetTypeConstructors(type).FirstOrDefault(ctor => this.CanConstruct(ctor, options));
|
||||
|
||||
private Boolean CanConstruct(MethodBase ctor, DependencyContainerResolveOptions? options) {
|
||||
foreach(ParameterInfo parameter in ctor.GetParameters()) {
|
||||
if(String.IsNullOrEmpty(parameter.Name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean isParameterOverload = options!.ConstructorParameters.ContainsKey(parameter.Name);
|
||||
|
||||
if(parameter.ParameterType.IsPrimitive && !isParameterOverload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isParameterOverload && !this.CanResolve(new DependencyContainer.TypeRegistration(parameter.ParameterType), options.Clone())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<DependencyContainer.TypeRegistration> GetParentRegistrationsForType(Type resolveType) => this._dependencyContainer.Parent == null ? Array.Empty<DependencyContainer.TypeRegistration>() : this._dependencyContainer.Parent.RegisteredTypes.Keys.Where(tr => tr.Type == resolveType).Concat(this._dependencyContainer.Parent.RegisteredTypes.GetParentRegistrationsForType(resolveType));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user