You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/DependencyInjection/Container.cs

1312 lines
46 KiB

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using ZeroLevel.Services.Collections;
namespace ZeroLevel.DependencyInjection
{
internal sealed class Container :
IContainer
{
#region Activator
private static object Activate(Type type, object[] args)
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public;
CultureInfo culture = null; // use InvariantCulture or other if you prefer
return Activator.CreateInstance(type, flags, null, args, culture);
}
public T CreateInstance<T>(string resolveName = "")
{
T instance = default(T);
try
{
instance = Resolve<T>(resolveName);
}
catch
{
instance = (T)Activate(typeof(T), null);
}
Compose(instance);
return instance;
}
public T CreateInstance<T>(object[] args, string resolveName = "")
{
T instance = default(T);
try
{
instance = Resolve<T>(resolveName, args);
}
catch
{
instance = (T)Activate(typeof(T), args);
}
Compose(instance);
return instance;
}
public object CreateInstance(Type type, string resolveName = "")
{
object instance = null;
try
{
instance = Resolve(type, resolveName);
}
catch
{
instance = Activate(type, null);
}
Compose(instance);
return instance;
}
public object CreateInstance(Type type, object[] args, string resolveName = "")
{
object instance = null;
try
{
instance = Resolve(type, resolveName, args);
}
catch
{
instance = Activate(type, args);
}
Compose(instance);
return instance;
}
#endregion Activator
#region Caching
private readonly ReaderWriterLockSlim _rwLock =
new ReaderWriterLockSlim();
/// <summary>
/// Map - contract - dependency resolving
/// </summary>
private readonly Dictionary<Type, List<ResolveTypeInfo>> _resolvingMap =
new Dictionary<Type, List<ResolveTypeInfo>>();
private readonly object _constructorCacheeLocker = new object();
/// <summary>
/// Types constructors cache
/// </summary>
private readonly Dictionary<Type, IEnumerable<ConstructorMetadata>> _constructorCachee =
new Dictionary<Type, IEnumerable<ConstructorMetadata>>();
#endregion Caching
#region Private
/// <summary>
/// Creating an instance of an object at the specified dependency resolution
/// </summary>
/// <param name="resolveType">Dependency resolving metadata</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeResolving(ResolveTypeInfo resolveType, object[] args, bool compose = true)
{
Type instanceType = resolveType.ImplementationType;
if (resolveType.IsShared)
{
if (null == resolveType.SharedInstance)
{
resolveType.SharedInstance = MakeInstance(instanceType, args ?? resolveType.ConstructorParameters);
if (compose)
{
Compose(resolveType.SharedInstance);
}
}
return resolveType.SharedInstance;
}
var sessionInstance = MakeInstance(instanceType, args ?? resolveType.ConstructorParameters);
if (compose)
{
Compose(sessionInstance);
}
return sessionInstance;
}
/// <summary>
/// Creating an instance of the object at the specified dependency resolution, for a generic type of contract
/// </summary>
/// <param name="resolveType">Dependency resolving metadata</param>
/// <param name="genericType">Generic contract</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeGenericResolving(ResolveTypeInfo resolveType, Type genericType, object[] args, bool compose = true)
{
if (null == resolveType.GenericCachee)
{
resolveType.GenericCachee = new Dictionary<Type, Type>();
}
if (false == resolveType.GenericCachee.ContainsKey(genericType))
{
var genericArgumentTypes = genericType.GetGenericArguments();
var realType = resolveType.ImplementationType.MakeGenericType(genericArgumentTypes);
resolveType.GenericCachee.Add(genericType, realType);
}
Type instanceType = resolveType.GenericCachee[genericType];
if (resolveType.IsShared)
{
if (resolveType.GenericInstanceCachee == null)
{
resolveType.GenericInstanceCachee = new Dictionary<Type, object>();
}
if (false == resolveType.GenericInstanceCachee.ContainsKey(instanceType))
{
var sharedInstance = MakeInstance(instanceType, args ?? resolveType.ConstructorParameters);
if (compose)
{
Compose(sharedInstance);
}
resolveType.GenericInstanceCachee.Add(instanceType, sharedInstance);
}
return resolveType.GenericInstanceCachee[instanceType];
}
var sessionInstance = MakeInstance(instanceType, args ?? resolveType.ConstructorParameters);
if (compose)
{
Compose(sessionInstance);
}
return sessionInstance;
}
/// <summary>
/// Collecting properties of the type marked with attribute dependency resolution
/// </summary>
/// <param name="type">Type</param>
/// <returns>List of properties marked with "Resolve" attribute</returns>
private static IEnumerable<PropertyInfo> CollectResolvingProperties(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy).
Where(p => p.GetCustomAttribute<ResolveAttribute>() != null);
}
/// <summary>
/// Collecting fields of type marked with an attribute of dependency resolution
/// </summary>
/// <param name="type">Type</param>
/// <returns>List of properties marked with "Resolve" attribute</returns>
private static IEnumerable<FieldInfo> CollectResolvingFields(Type type)
{
return type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy).
Where(p => p.GetCustomAttribute<ResolveAttribute>() != null);
}
/// <summary>
/// Search for dependency resolution
/// </summary>
/// <param name="type">Contract</param>
/// <param name="resolveName">Dependency name</param>
/// <param name="contractType">Redefined contract type</param>
/// <returns></returns>
private ResolveTypeInfo FindResolving(Type type, string resolveName, Type contractType)
{
HashSet<Type> contract_candidates = new HashSet<Type>();
if (contractType != null)
{
if (contractType.IsInterface)
contract_candidates.Add(contractType);
foreach (var c in GetInterfacesAndAbstracts(contractType))
contract_candidates.Add(c);
}
if (contract_candidates.Count == 0)
{
if (type.IsInterface)
contract_candidates.Add(type);
foreach (var c in GetInterfacesAndAbstracts(type))
contract_candidates.Add(c);
}
if (contract_candidates.Count > 0)
{
try
{
_rwLock.EnterReadLock();
var resolveInfo = _resolvingMap.Single(r => contract_candidates.Any(ct => ct == r.Key));
return resolveInfo.Value.First(ri => ri.ResolveKey.Equals(resolveName, StringComparison.OrdinalIgnoreCase));
}
finally
{
_rwLock.ExitReadLock();
}
}
throw new KeyNotFoundException($"Can't resolve dependency by type '{type.FullName}' and dependency name '{resolveName}'");
}
/// <summary>
/// Resolving dependency on attribute "Resolve
/// </summary>
/// <param name="type">Contract</param>
/// <param name="resolveAttribute">Resolve attribute</param>
/// <returns>Instance</returns>
private object MakeInstanceBy(Type type, ResolveAttribute resolveAttribute)
{
var is_generic = false;
var maybyType = type;
if (maybyType.IsGenericTypeDefinition)
{
maybyType = maybyType.GetGenericTypeDefinition();
is_generic = true;
}
var resolveType = FindResolving(maybyType,
resolveAttribute?.ResolveName ?? string.Empty,
resolveAttribute?.ContractType);
try
{
if (is_generic)
return MakeGenericResolving(resolveType, type, null);
return MakeResolving(resolveType, null);
}
catch (Exception ex)
{
throw new Exception($"Can't create type '{type.FullName}' instance for contract type {type.FullName}. Dependency key: '{resolveAttribute?.ResolveName}'", ex);
}
}
/// <summary>
/// Collection of interfaces and abstract classes from which the type is inherited
/// </summary>
/// <param name="sourceType">Type</param>
/// <returns>List of interfaces and abstract classes</returns>
private static IEnumerable<Type> GetInterfacesAndAbstracts(Type sourceType)
{
var interfaces = sourceType.GetInterfaces().ToList();
var parent = sourceType.BaseType;
while (parent != null && parent != typeof(object))
{
if (parent.IsAbstract && parent.IsClass)
interfaces.Add(parent);
parent = parent.BaseType;
}
return interfaces;
}
/// <summary>
/// Getting a list of metadata by type constructors
/// </summary>
/// <param name="type">Type</param>
/// <returns>Metadata type constructors</returns>
private IEnumerable<ConstructorMetadata> GetConstructors(Type type)
{
lock (_constructorCacheeLocker)
{
if (false == _constructorCachee.ContainsKey(type))
{
var list = new List<ConstructorMetadata>();
foreach (var c in type.
GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
list.Add(new ConstructorMetadata(this, c));
}
_constructorCachee.Add(type, list);
}
}
return _constructorCachee[type];
}
/// <summary>
/// Creating an instance of an object, including with non-public constructors
/// </summary>
/// <param name="type">Type</param>
/// <param name="args">Ctor args</param>
/// <returns>Instance</returns>
private object MakeInstance(Type type, object[] args)
{
ConstructorInfo constructor = null;
object[] parameters = null;
foreach (var ctor in GetConstructors(type))
{
if (ctor.IsMatch(args, out parameters))
{
constructor = ctor.Constructor;
break;
}
}
if (null == constructor)
{
return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
}
else
{
return constructor.Invoke(parameters);
/*var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public;
CultureInfo culture = null; // use InvariantCulture or other if you prefer
return Activator.CreateInstance(type, flags, null, args, culture);*/
}
}
/// <summary>
/// Dependency resolution registration
/// </summary>
/// <param name="contractType">Contract</param>
/// <param name="resolveType">Dependency resolving metadata</param>
private void Register(Type contractType, ResolveTypeInfo resolveType)
{
try
{
_rwLock.EnterUpgradeableReadLock();
if (false == _resolvingMap.ContainsKey(contractType))
{
try
{
_rwLock.EnterWriteLock();
_resolvingMap.Add(contractType, new List<ResolveTypeInfo>());
}
finally
{
_rwLock.ExitWriteLock();
}
}
else
{
if (resolveType.IsDefault &&
_resolvingMap[contractType].Any(it => it.IsDefault))
{
throw new Exception($"Default resolve type already has been defined. Contract: {contractType.FullName}");
}
if (_resolvingMap[contractType].
Any(it => it.ResolveKey.Equals(resolveType.ResolveKey, StringComparison.OrdinalIgnoreCase)))
{
throw new Exception($"Resolve type with the same name '{resolveType.ResolveKey}' already has been defined. Contract: { contractType.FullName}");
}
}
try
{
_rwLock.EnterWriteLock();
_resolvingMap[contractType].Add(resolveType);
}
finally
{
_rwLock.ExitWriteLock();
}
}
finally
{
_rwLock.ExitUpgradeableReadLock();
}
}
#endregion Private
#region Register
public void Register<TContract, TImplementation>()
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = true,
IsShared = false,
ResolveKey = string.Empty
};
Register(typeof(TContract), resolveType);
}
public void Register<TContract, TImplementation>(bool shared)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = true,
IsShared = shared,
ResolveKey = string.Empty
};
Register(typeof(TContract), resolveType);
}
public void Register<TContract, TImplementation>(string resolveName)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = false,
ResolveKey = resolveName?.Trim()
};
Register(typeof(TContract), resolveType);
}
public void Register<TContract, TImplementation>(string resolveName, bool shared)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = shared,
ResolveKey = resolveName?.Trim()
};
Register(typeof(TContract), resolveType);
}
public void Register(Type contractType, Type implementationType)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = true,
IsShared = false,
ResolveKey = string.Empty
};
Register(contractType, resolveType);
}
public void Register(Type contractType, Type implementationType, string resolveName)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = false,
ResolveKey = resolveName?.Trim()
};
Register(contractType, resolveType);
}
public void Register(Type contractType, Type implementationType, bool shared)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = true,
IsShared = shared,
ResolveKey = string.Empty
};
Register(contractType, resolveType);
}
public void Register(Type contractType, Type implementationType, string resolveName, bool shared)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = shared,
ResolveKey = resolveName?.Trim()
};
Register(contractType, resolveType);
}
#endregion Register
#region Register with parameters
public void ParameterizedRegister<TContract, TImplementation>(object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = true,
IsShared = false,
ResolveKey = string.Empty,
ConstructorParameters = constructorParameters
};
Register(typeof(TContract), resolveType);
}
public void ParameterizedRegister<TContract, TImplementation>(string resolveName, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = false,
ResolveKey = resolveName?.Trim(),
ConstructorParameters = constructorParameters
};
Register(typeof(TContract), resolveType);
}
public void ParameterizedRegister<TContract, TImplementation>(bool shared, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = true,
IsShared = shared,
ResolveKey = string.Empty,
ConstructorParameters = constructorParameters
};
Register(typeof(TContract), resolveType);
}
public void ParameterizedRegister<TContract, TImplementation>(string resolveName, bool shared, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = typeof(TImplementation),
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = shared,
ResolveKey = resolveName?.Trim(),
ConstructorParameters = constructorParameters
};
Register(typeof(TContract), resolveType);
}
public void ParameterizedRegister(Type contractType, Type implementationType, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = true,
IsShared = false,
ResolveKey = string.Empty,
ConstructorParameters = constructorParameters
};
Register(contractType, resolveType);
}
public void ParameterizedRegister(Type contractType, Type implementationType, string resolveName, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = false,
ResolveKey = resolveName?.Trim(),
ConstructorParameters = constructorParameters
};
Register(contractType, resolveType);
}
public void ParameterizedRegister(Type contractType, Type implementationType, bool shared, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = true,
IsShared = shared,
ResolveKey = string.Empty,
ConstructorParameters = constructorParameters
};
Register(contractType, resolveType);
}
public void ParameterizedRegister(Type contractType, Type implementationType, string resolveName, bool shared, object[] constructorParameters)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementationType,
IsDefault = string.IsNullOrWhiteSpace(resolveName),
IsShared = shared,
ResolveKey = resolveName?.Trim(),
ConstructorParameters = constructorParameters
};
Register(contractType, resolveType);
}
#endregion Register with parameters
#region Register instance
/// <summary>
/// Register singletone
/// </summary>
/// <typeparam name="TContract">Contract</typeparam>
/// <param name="implementation">Instance</param>
public void Register<TContract>(TContract implementation)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation.GetType(),
IsDefault = true,
IsShared = true,
ResolveKey = string.Empty,
SharedInstance = implementation
};
Register(typeof(TContract), resolveType);
}
public void Register(Type contractType, object implementation)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation.GetType(),
IsDefault = true,
IsShared = true,
ResolveKey = string.Empty,
SharedInstance = implementation
};
Register(contractType, resolveType);
}
public void Register<TContract>(TContract implementation, string resolveName)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation.GetType(),
IsDefault = string.IsNullOrEmpty(resolveName),
IsShared = true,
ResolveKey = resolveName,
SharedInstance = implementation
};
Register(typeof(TContract), resolveType);
}
public void Register(Type contractType, string resolveName, object implementation)
{
var resolveType = new ResolveTypeInfo
{
ImplementationType = implementation.GetType(),
IsDefault = true,
IsShared = true,
ResolveKey = resolveName,
SharedInstance = implementation
};
Register(contractType, resolveType);
}
#endregion Register instance
#region Safe register
public bool TryRegister<TContract, TImplementation>(Action<Exception> fallback = null)
{
try
{
Register<TContract, TImplementation>();
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister<TContract, TImplementation>(bool shared, Action<Exception> fallback = null)
{
try
{
Register<TContract, TImplementation>(shared);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister<TContract, TImplementation>(string resolveName, Action<Exception> fallback = null)
{
try
{
Register<TContract, TImplementation>(resolveName);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister<TContract, TImplementation>(string resolveName, bool shared, Action<Exception> fallback = null)
{
try
{
Register<TContract, TImplementation>(resolveName, shared);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister(Type contractType, Type implementationType, Action<Exception> fallback = null)
{
try
{
Register(contractType, implementationType);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister(Type contractType, Type implementationType, string resolveName, Action<Exception> fallback = null)
{
try
{
Register(contractType, implementationType, resolveName);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister(Type contractType, Type implementationType, bool shared, Action<Exception> fallback = null)
{
try
{
Register(contractType, implementationType, shared);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryRegister(Type contractType, Type implementationType, string resolveName, bool shared, Action<Exception> fallback = null)
{
try
{
Register(contractType, implementationType, resolveName, shared);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
#endregion Safe register
#region Safe register with parameters
public bool TryParameterizedRegister<TContract, TImplementation>(object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister<TContract, TImplementation>(constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister<TContract, TImplementation>(string resolveName, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister<TContract, TImplementation>(resolveName, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister<TContract, TImplementation>(bool shared, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister<TContract, TImplementation>(shared, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister<TContract, TImplementation>(string resolveName, bool shared, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister<TContract, TImplementation>(resolveName, shared, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister(Type contractType, Type implementationType, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister(contractType, implementationType, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister(Type contractType, Type implementationType, string resolveName, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister(contractType, implementationType, resolveName, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister(Type contractType, Type implementationType, bool shared, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister(contractType, implementationType, shared, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
public bool TryParameterizedRegister(Type contractType, Type implementationType, string resolveName, bool shared, object[] constructorParameters, Action<Exception> fallback = null)
{
try
{
ParameterizedRegister(contractType, implementationType, resolveName, shared, constructorParameters);
return true;
}
catch (Exception ex)
{
fallback?.Invoke(ex);
return false;
}
}
#endregion Safe register with parameters
#region Resolving
public object Resolve(Type type, bool compose = true)
{
return Resolve(type, string.Empty, null, compose);
}
public object Resolve(Type type, object[] args, bool compose = true)
{
return Resolve(type, string.Empty, args, compose);
}
public object Resolve(Type type, string resolveName, bool compose = true)
{
return Resolve(type, resolveName, null, compose);
}
public T Resolve<T>(bool compose = true)
{
return (T)Resolve(typeof(T), string.Empty, null, compose);
}
public T Resolve<T>(object[] args, bool compose = true)
{
return (T)Resolve(typeof(T), string.Empty, args, compose);
}
public T Resolve<T>(string resolveName, bool compose = true)
{
return (T)Resolve(typeof(T), resolveName, null, compose);
}
public T Resolve<T>(string resolveName, object[] args, bool compose = true)
{
return (T)Resolve(typeof(T), resolveName, args, compose);
}
public bool IsResolvingExists<T>()
{
return IsResolvingExists(typeof(T), string.Empty);
}
public bool IsResolvingExists<T>(string resolveName)
{
return IsResolvingExists(typeof(T), resolveName);
}
public bool IsResolvingExists(Type type)
{
return IsResolvingExists(type, string.Empty);
}
public bool IsResolvingExists(Type type, string resolveName)
{
return GetResolvedType(type, resolveName)?.Item1 != null;
}
private Tuple<ResolveTypeInfo, bool> GetResolvedType(Type type, string resolveName)
{
try
{
_rwLock.EnterReadLock();
if (_resolvingMap.ContainsKey(type))
{
return Tuple.Create(_resolvingMap[type].
FirstOrDefault(i => i.ResolveKey.Equals(resolveName, StringComparison.Ordinal)),
false);
}
else if (type.IsGenericType)
{
var generic_type = type.GetGenericTypeDefinition();
if (_resolvingMap.ContainsKey(generic_type))
{
return Tuple.Create(_resolvingMap[generic_type].
FirstOrDefault(i => i.ResolveKey.Equals(resolveName, StringComparison.Ordinal)),
true);
}
}
}
finally
{
_rwLock.ExitReadLock();
}
return new Tuple<ResolveTypeInfo, bool>(null, false);
}
public object Resolve(Type type, string resolveName, object[] args, bool compose = true)
{
var resolve = GetResolvedType(type, resolveName);
if (null == resolve.Item1)
throw new KeyNotFoundException($"Can'r resolve type {type.FullName} on key '{resolveName}'");
// Detect instance type
try
{
if (resolve.Item2)
{
return MakeGenericResolving(resolve.Item1, type, args, compose);
}
return MakeResolving(resolve.Item1, args, compose);
}
catch (Exception ex)
{
throw new Exception($"Can't create instance for type {type.FullName} for resolved dependency {type.FullName} by key {resolveName}", ex);
}
}
#endregion Resolving
#region Safe resolving
public object TryResolve(Type type, out object result, bool compose = true)
{
return TryResolve(type, string.Empty, null, out result, compose);
}
public object TryResolve(Type type, object[] args, out object result, bool compose = true)
{
return TryResolve(type, string.Empty, args, out result, compose);
}
public object TryResolve(Type type, string resolveName, out object result, bool compose = true)
{
return TryResolve(type, resolveName, null, out result, compose);
}
public bool TryResolve<T>(out T result, bool compose = true)
{
object instance;
if (TryResolve(typeof(T), string.Empty, null, out instance, compose))
{
result = (T)instance;
return true;
}
result = default(T);
return false;
}
public bool TryResolve<T>(object[] args, out T result, bool compose = true)
{
object instance;
if (TryResolve(typeof(T), string.Empty, args, out instance, compose))
{
result = (T)instance;
return true;
}
result = default(T);
return false;
}
public bool TryResolve<T>(string resolveName, out T result, bool compose = true)
{
object instance;
if (TryResolve(typeof(T), resolveName, null, out instance, compose))
{
result = (T)instance;
return true;
}
result = default(T);
return false;
}
public bool TryResolve<T>(string resolveName, object[] args, out T result, bool compose = true)
{
object instance;
if (TryResolve(typeof(T), resolveName, args, out instance, compose))
{
result = (T)instance;
return true;
}
result = default(T);
return false;
}
public bool TryResolve(Type type, string resolveName, object[] args, out object result, bool compose = true)
{
// Detect instance type
var resolve = GetResolvedType(type, resolveName);
if (null == resolve.Item1)
{
result = null;
return false;
}
try
{
if (resolve.Item2)
{
result = MakeGenericResolving(resolve.Item1, type, args, compose);
}
else
{
result = MakeResolving(resolve.Item1, args, compose);
}
return true;
}
catch (Exception ex)
{
Log.SystemWarning(
$"Can't create type '{type.FullName}' instance for resolve dependency with contract type '{type.FullName}' and dependency name '{resolveName}'", ex);
}
result = null;
return false;
}
#endregion Safe resolving
#region Composition
/// <summary>
/// Filling in the fields and properties of an object with auto-set values flagged from the container parameters
/// </summary>
private void FillParametrizedFieldsAndProperties(object instance)
{
foreach (var property in instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy))
{
var attr = property.GetCustomAttribute<ParameterAttribute>();
if (attr != null)
{
var parameterType = attr.Type ?? property.PropertyType;
var parameterName = attr.Name ?? property.Name;
property.SetValue(instance, this.Get(parameterType, parameterName));
}
}
foreach (var field in instance.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy))
{
var attr = field.GetCustomAttribute<ParameterAttribute>();
if (attr != null)
{
var parameterType = attr.Type ?? field.FieldType;
var parameterName = string.IsNullOrWhiteSpace(attr.Name) ? field.Name : attr.Name;
field.SetValue(instance, this.Get(parameterType, parameterName));
}
}
}
private void ComposeParts(object instance)
{
var resolve_properties = CollectResolvingProperties(instance.GetType());
var resolve_fields = CollectResolvingFields(instance.GetType());
foreach (var p in resolve_properties)
{
var resolve_instance = MakeInstanceBy(p.PropertyType,
p.GetCustomAttribute<ResolveAttribute>());
p.SetValue(instance, resolve_instance);
}
foreach (var f in resolve_fields)
{
var resolve_instance = MakeInstanceBy(f.FieldType,
f.GetCustomAttribute<ResolveAttribute>());
f.SetValue(instance, resolve_instance);
}
FillParametrizedFieldsAndProperties(instance);
}
private void RecursiveCompose(object instance, HashSet<object> set)
{
foreach (var f in
instance.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance))
{
if (f.FieldType.IsClass || f.FieldType.IsInterface)
{
var next = f.GetValue(instance);
if (null != next)
{
if (set.Add(next))
{
RecursiveCompose(next, set);
}
}
}
}
ComposeParts(instance);
}
public void Compose(object instance, bool recursive = true)
{
if (recursive)
{
RecursiveCompose(instance, new HashSet<object>());
}
else
{
ComposeParts(instance);
}
}
public bool TryCompose(object instanse, bool recursive = true)
{
try
{
Compose(instanse, recursive);
return true;
}
catch (Exception ex)
{
Log.SystemError(ex, $"[Container] TryCompose error. Instance: '{instanse?.GetType()?.FullName ?? string.Empty}'. Recursive: {recursive}");
}
return false;
}
#endregion Composition
#region IDisposable
public void Dispose()
{
try
{
_rwLock.EnterWriteLock();
foreach (var list in _resolvingMap.Values)
{
foreach (var item in list)
{
try
{
(item.SharedInstance as IDisposable)?.Dispose();
}
catch (Exception ex)
{
Log.SystemError(ex, $"[Container] Singletone dispose error. Instance: '{item?.GetType()?.FullName ?? string.Empty}'");
}
if (item.GenericInstanceCachee != null)
{
foreach (var gitem in item.GenericInstanceCachee.Values)
{
try
{
(gitem as IDisposable)?.Dispose();
}
catch (Exception ex)
{
Log.SystemError(ex, $"[Container] Generic singletone dispose error. Instance: '{gitem?.GetType()?.FullName ?? string.Empty}'");
}
}
}
}
}
}
catch (Exception ex)
{
Log.SystemError(ex, $"[Container] Dispose error");
}
finally
{
_rwLock.ExitWriteLock();
}
}
#endregion IDisposable
#region IEverythingStorage
private readonly Lazy<IEverythingStorage> _everything =
new Lazy<IEverythingStorage>(EverythingStorage.Create);
public void Save<T>(string key, T value)
{
_everything.Value.Add<T>(key, value);
}
public void Remove<T>(string key)
{
_everything.Value.Remove<T>(key);
}
public bool Contains<T>(string key)
{
return _everything.Value.ContainsKey<T>(key);
}
public bool TrySave<T>(string key, T value)
{
return _everything.Value.TryAdd<T>(key, value);
}
public bool TryRemove<T>(string key)
{
return _everything.Value.TryRemove<T>(key);
}
public T Get<T>(string key)
{
return _everything.Value.Get<T>(key);
}
public object Get(Type type, string key)
{
return _everything.Value.Get(type, key);
}
public void SaveOrUpdate<T>(string key, T value)
{
_everything.Value.AddOrUpdate<T>(key, value);
}
public T GetOrDefault<T>(string key)
{
if (_everything.Value.ContainsKey<T>(key))
return _everything.Value.Get<T>(key);
return default(T);
}
public T GetOrDefault<T>(string key, T defaultValue)
{
if (_everything.Value.ContainsKey<T>(key))
return _everything.Value.Get<T>(key);
return defaultValue;
}
#endregion IEverythingStorage
}
}

Powered by TurnKey Linux.