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> /// 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 Boolean 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(this.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(this.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(this.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(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(); } }