using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; using ZeroLevel.Services.Collections; namespace ZeroLevel.Patterns.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(string resolveName = "") { T instance = default(T); try { instance = Resolve(resolveName); } catch { instance = (T)Activate(typeof(T), null); } Compose(instance); return instance; } public T CreateInstance(object[] args, string resolveName = "") { T instance = default(T); try { instance = Resolve(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 #region Caching private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); /// /// Маппинг контракт - резрешения /// private readonly Dictionary> _resolvingMap = new Dictionary>(); private readonly object _constructorCacheeLocker = new object(); /// /// Кэш данных о контрукторах типа /// private readonly Dictionary> _constructorCachee = new Dictionary>(); #endregion #region Private /// /// Создание экземпляра объекта по указанному разрешению зависимости /// /// Метаданные разрешения зависимости /// Аргументы конструктора /// Экземпляр объекта 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; } /// /// Создание экземпляра объекта по указанному разрешению зависимости, для обобщенного типа контракта /// /// Метаданные разрешения зависимости /// Обобщенный тип контракта /// Аргументы конструктора /// Экземпляр объекта private object MakeGenericResolving(ResolveTypeInfo resolveType, Type genericType, object[] args, bool compose = true) { if (null == resolveType.GenericCachee) { resolveType.GenericCachee = new Dictionary(); } 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(); } 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; } /// /// Сбор свойств типа помеченных аттрибутом разрешения зависимости /// /// Тип /// Список свойств отмеченных аттрибутом Resolve private static IEnumerable CollectResolvingProperties(Type type) { return type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy). Where(p => p.GetCustomAttribute() != null); } /// /// Сбор полей типа помеченных аттрибутом разрешения зависимости /// /// Тип /// Список полей отмеченных аттрибутом Resolve private static IEnumerable CollectResolvingFields(Type type) { return type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy). Where(p => p.GetCustomAttribute() != null); } /// /// Поиск разрешения зависимости /// /// Тип контракта /// Имя разрешения зависимости /// Переопределенный тип контракта /// private ResolveTypeInfo FindResolving(Type type, string resolveName, Type contractType) { HashSet contract_candidates = new HashSet(); 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(string.Format("Не удалось разрешить зависимость для типа {0} по ключу '{1}'", type.FullName, resolveName)); } /// /// Разрешение зависимости по аттрибуту Resolve /// /// Тип контракта /// Аттрибут /// Экземпляр объекта 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( string.Format("Не удалось создать экземпляр типа {0} для разрешения зависимости типа {1} по ключу {2}", type.FullName, type.FullName, resolveAttribute?.ResolveName), ex); } } /// /// Сбор интерфейсов и абстрактных классов от которых унаследован тип /// /// Тип /// Список интерфейсов и абстрактных классов private static IEnumerable 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; } /// /// Получение списка метаданных по конструкторам типа /// /// Тип /// Метаданные о конструкторах типа private IEnumerable GetConstructors(Type type) { lock (_constructorCacheeLocker) { if (false == _constructorCachee.ContainsKey(type)) { var list = new List(); 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]; } /// /// Создание экземпляра объекта, в том числе с непубличными конструкторами /// /// Тип /// Аргументы конструктора /// Экземпляр типа 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);*/ } } /// /// Регистрация разрешения зависимости /// /// Тип контракта /// Метаданные разрешения private void Register(Type contractType, ResolveTypeInfo resolveType) { try { _rwLock.EnterUpgradeableReadLock(); if (false == _resolvingMap.ContainsKey(contractType)) { try { _rwLock.EnterWriteLock(); _resolvingMap.Add(contractType, new List()); } finally { _rwLock.ExitWriteLock(); } } else { if (resolveType.IsDefault && _resolvingMap[contractType].Any(it => it.IsDefault)) { throw new Exception( string.Format("Default resolve type already has been defined. Contract: {0}", contractType.FullName)); } if (_resolvingMap[contractType]. Any(it => it.ResolveKey.Equals(resolveType.ResolveKey, StringComparison.OrdinalIgnoreCase))) { throw new Exception( string.Format("Resolve type with the same name '{0}' already has been defined. Contract: {1}", resolveType.ResolveKey, contractType.FullName)); } } try { _rwLock.EnterWriteLock(); _resolvingMap[contractType].Add(resolveType); } finally { _rwLock.ExitWriteLock(); } } finally { _rwLock.ExitUpgradeableReadLock(); } } #endregion #region Register public void Register() { var resolveType = new ResolveTypeInfo { ImplementationType = typeof(TImplementation), IsDefault = true, IsShared = false, ResolveKey = string.Empty }; Register(typeof(TContract), resolveType); } public void Register(bool shared) { var resolveType = new ResolveTypeInfo { ImplementationType = typeof(TImplementation), IsDefault = true, IsShared = shared, ResolveKey = string.Empty }; Register(typeof(TContract), resolveType); } public void Register(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(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 #region Register with parameters public void ParameterizedRegister(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(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(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(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 #region Register instance /// /// Регистрация готового экземпляра (синглтон) /// /// Тип контракта /// Экземпляр public void Register(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 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 #region Safe register public bool TryRegister(Action fallback = null) { try { Register(); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryRegister(bool shared, Action fallback = null) { try { Register(shared); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryRegister(string resolveName, Action fallback = null) { try { Register(resolveName); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryRegister(string resolveName, bool shared, Action fallback = null) { try { Register(resolveName, shared); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryRegister(Type contractType, Type implementationType, Action 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 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 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 fallback = null) { try { Register(contractType, implementationType, resolveName, shared); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } #endregion #region Safe register with parameters public bool TryParameterizedRegister(object[] constructorParameters, Action fallback = null) { try { ParameterizedRegister(constructorParameters); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryParameterizedRegister(string resolveName, object[] constructorParameters, Action fallback = null) { try { ParameterizedRegister(resolveName, constructorParameters); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryParameterizedRegister(bool shared, object[] constructorParameters, Action fallback = null) { try { ParameterizedRegister(shared, constructorParameters); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryParameterizedRegister(string resolveName, bool shared, object[] constructorParameters, Action fallback = null) { try { ParameterizedRegister(resolveName, shared, constructorParameters); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } public bool TryParameterizedRegister(Type contractType, Type implementationType, object[] constructorParameters, Action 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 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 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 fallback = null) { try { ParameterizedRegister(contractType, implementationType, resolveName, shared, constructorParameters); return true; } catch (Exception ex) { fallback?.Invoke(ex); return false; } } #endregion #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(bool compose = true) { return (T)Resolve(typeof(T), string.Empty, null, compose); } public T Resolve(object[] args, bool compose = true) { return (T)Resolve(typeof(T), string.Empty, args, compose); } public T Resolve(string resolveName, bool compose = true) { return (T)Resolve(typeof(T), resolveName, null, compose); } public T Resolve(string resolveName, object[] args, bool compose = true) { return (T)Resolve(typeof(T), resolveName, args, compose); } public bool IsResolvingExists() { return IsResolvingExists(typeof(T), string.Empty); } public bool IsResolvingExists(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 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(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(string.Format("Can'r resolve type {0} on key '{1}'", type.FullName, 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( string.Format("Can't create instance for type {0} for resolved dependency {1} by key {2}", type.FullName, type.FullName, resolveName), ex); } } #endregion #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(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(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(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(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( string.Format("Не удалось создать экземпляр типа {0} для разрешения зависимости типа {1} по ключу {2}", type.FullName, type.FullName, resolveName), ex); } result = null; return false; } #endregion #region Composition /// /// Заполнение полей и свойств объекта отмеченных флагом автоподставновки значений из параметров контейнера /// private void FillParametrizedFieldsAndProperties(object instance) { foreach (var property in instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy)) { var attr = property.GetCustomAttribute(); 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(); 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()); p.SetValue(instance, resolve_instance); } foreach (var f in resolve_fields) { var resolve_instance = MakeInstanceBy(f.FieldType, f.GetCustomAttribute()); f.SetValue(instance, resolve_instance); } FillParametrizedFieldsAndProperties(instance); } private void RecursiveCompose(object instance, HashSet 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()); } else { ComposeParts(instance); } } public bool TryCompose(object instanse, bool recursive = true) { try { Compose(instanse, recursive); return true; } catch { } return false; } #endregion #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 { } if (item.GenericInstanceCachee != null) { foreach (var gitem in item.GenericInstanceCachee.Values) { try { (gitem as IDisposable)?.Dispose(); } catch { } } } } } } finally { _rwLock.ExitWriteLock(); } } #endregion #region IEverythingStorage private readonly Lazy _everything = new Lazy(EverythingStorage.Create); public void Save(string key, T value) { _everything.Value.Add(key, value); } public void Remove(string key) { _everything.Value.Remove(key); } public bool Contains(string key) { return _everything.Value.ContainsKey(key); } public bool TrySave(string key, T value) { return _everything.Value.TryAdd(key, value); } public bool TryRemove(string key) { return _everything.Value.TryRemove(key); } public T Get(string key) { return _everything.Value.Get(key); } public object Get(Type type, string key) { MethodInfo method = typeof(IEverythingStorage).GetMethod("Get"); MethodInfo genericMethod = method.MakeGenericMethod(type); return genericMethod.Invoke(_everything.Value, new object[] { key }); } public void SaveOrUpdate(string key, T value) { _everything.Value.AddOrUpdate(key, value); } public T GetOrDefault(string key) { if (_everything.Value.ContainsKey(key)) return _everything.Value.Get(key); return default(T); } public T GetOrDefault(string key, T defaultValue) { if (_everything.Value.ContainsKey(key)) return _everything.Value.Get(key); return defaultValue; } #endregion } }