using System; using System.Collections.Generic; using System.Reflection; namespace Swan.DependencyInjection { /// /// 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 Boolean 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(this.GetType(), "singleton"); /// /// Gets the multi instance variant. /// /// /// The multi instance variant. /// /// multi-instance. public virtual ObjectFactoryBase MultiInstanceVariant => throw new DependencyContainerRegistrationException(this.GetType(), "multi-instance"); /// /// Gets the strong reference variant. /// /// /// The strong reference variant. /// /// strong reference. public virtual ObjectFactoryBase StrongReferenceVariant => throw new DependencyContainerRegistrationException(this.GetType(), "strong reference"); /// /// Gets the weak reference variant. /// /// /// The weak reference variant. /// /// weak reference. public virtual ObjectFactoryBase WeakReferenceVariant => throw new DependencyContainerRegistrationException(this.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) => 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); } 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); } } } /// /// /// 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) { 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); } } } /// /// /// 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)); } 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, 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, 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); } } } /// /// 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); } 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(); } } /// /// 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); } 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(); } /// /// 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); } 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(); } }