namespace Swan.DependencyInjection
{
using System;
using System.Collections.Generic;
using System.Reflection;
///
/// Represents an abstract class for Object Factory.
///
public abstract class ObjectFactoryBase
{
///
/// 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.
///
public virtual bool AssumeConstruction => false;
///
/// The type the factory instantiates.
///
public abstract Type CreatesType { get; }
///
/// Constructor to use, if specified.
///
public ConstructorInfo Constructor { get; private set; }
///
/// Gets the singleton variant.
///
///
/// The singleton variant.
///
/// singleton.
public virtual ObjectFactoryBase SingletonVariant =>
throw new DependencyContainerRegistrationException(GetType(), "singleton");
///
/// Gets the multi instance variant.
///
///
/// The multi instance variant.
///
/// multi-instance.
public virtual ObjectFactoryBase MultiInstanceVariant =>
throw new DependencyContainerRegistrationException(GetType(), "multi-instance");
///
/// Gets the strong reference variant.
///
///
/// The strong reference variant.
///
/// strong reference.
public virtual ObjectFactoryBase StrongReferenceVariant =>
throw new DependencyContainerRegistrationException(GetType(), "strong reference");
///
/// Gets the weak reference variant.
///
///
/// The weak reference variant.
///
/// weak reference.
public virtual ObjectFactoryBase WeakReferenceVariant =>
throw new DependencyContainerRegistrationException(GetType(), "weak reference");
///
/// Create the type.
///
/// Type user requested to be resolved.
/// Container that requested the creation.
/// The options.
/// Instance of type.
public abstract object GetObject(
Type requestedType,
DependencyContainer container,
DependencyContainerResolveOptions options);
///
/// Gets the factory for child container.
///
/// The type.
/// The parent.
/// The child.
///
public virtual ObjectFactoryBase GetFactoryForChildContainer(
Type type,
DependencyContainer parent,
DependencyContainer child)
{
return this;
}
}
///
///
/// IObjectFactory that creates new instances of types for each resolution.
///
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);
}
}
}
///
///
/// IObjectFactory that invokes a specified delegate to construct the object.
///
internal class DelegateFactory : ObjectFactoryBase
{
private readonly Type _registerType;
private readonly Func, object> _factory;
public DelegateFactory(
Type registerType,
Func, 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);
}
}
}
///
///
/// IObjectFactory that invokes a specified delegate to construct the object
/// Holds the delegate using a weak reference.
///
internal class WeakDelegateFactory : ObjectFactoryBase
{
private readonly Type _registerType;
private readonly WeakReference _factory;
public WeakDelegateFactory(
Type registerType,
Func, 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, 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, object> factory))
throw new DependencyContainerWeakReferenceException(_registerType);
try
{
return factory.Invoke(container, options.ConstructorParameters);
}
catch (Exception ex)
{
throw new DependencyContainerResolutionException(_registerType, ex);
}
}
}
///
/// Stores an particular instance to return for a type.
///
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();
}
}
///
/// Stores the instance with a weak reference.
///
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();
}
///
/// A factory that lazy instantiates a type and always returns the same instance.
///
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();
}
}