391 lines
14 KiB
C#
391 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using Unosquare.Swan.Exceptions;
|
|
|
|
namespace Unosquare.Swan.Components {
|
|
/// <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();
|
|
}
|
|
}
|