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(); } }