/// <summary> /// Отменяет регистрацию компонента /// </summary> /// <param name="component"> компонент, который должен быть убран из контейнера </param> /// <remarks> /// <note>Очевидно что, такой метод обязан присутствовать в интерфейсе контейнера, однако его использование в задачах помимо тестирования, /// обозначает недостатки архитектуры приложения, так как в нормальном варианте использования контейнер меняет свое поведение по принципу наращивания /// обслуживаемых классов и компонентов, тогда как удаление части компонент может привести к неожиданным эффектам в случае кэширования более /// ранеей выдвачи клиентской стороной</note> /// </remarks> public void Unregister(IComponentDefinition component) { lock (this) { if (null == component) { return; } if (!Components.Contains(component)) { return; } Components.Remove(component); ByTypeCache[component.ServiceType].Remove(component); if (component.Name.IsNotEmpty()) { ByNameCache[component.Name].Remove(component); } foreach (var componentDefinition in OutgoingCache.ToArray()) { if (Equals(componentDefinition.Value, component)) { DropObject(componentDefinition.Key); OutgoingCache.Remove(componentDefinition.Key); } } if (Lifestyle.PerThread == component.Lifestyle) { foreach (var threadCache in ThreadOutgoingCache.ToArray()) { foreach (var componentDefinition in threadCache.Value.ToArray()) { if (Equals(componentDefinition.Value, component)) { DropObject(componentDefinition.Key); OutgoingCache.Remove(componentDefinition.Key); } } } } if (Lifestyle.Pooled == component.Lifestyle) { if (Pool.ContainsKey(component)) { foreach (var obj in Pool[component]) { DropObject(obj); } Pool.Remove(component); } } // hook for extensions - UnRegisterComponent extensions can do something after it's // native unregistration ProcessExtensions(new ContainerContext { Operation = ContainerOperation.UnregisterComponent, Component = component }); } }
/// <summary> /// Возвращает объект контейнеру /// </summary> /// <param name="obj"> Объект, ранее созданнй контейнером </param> /// <remarks> /// <invariant>Метод позволяет контейнеру высвобождать собственные ресурсы и вызывает /// <see cref="IContainerBound.OnContainerRelease" /> /// метод, /// работает это только для /// <see cref="Lifestyle.Pooled" /> /// и /// <see cref="Lifestyle.PerThread" /> /// , для остальных данный метод игнорируется</invariant> /// </remarks> public void Release(object obj) { lock (this) { if (!OutgoingCache.ContainsKey(obj)) { return; } var component = OutgoingCache[obj]; switch (component.Lifestyle) { case Lifestyle.Extension: //extensions not must be released goto case Lifestyle.Transient; case Lifestyle.Default: // default is transient goto case Lifestyle.Transient; case Lifestyle.Transient: //transient not have to be released return; case Lifestyle.Pooled: // pool ion release not disposed, but moved to pool if (!Pool.ContainsKey(component)) { Pool[component] = new Stack <object>(); } Pool[component].Push(obj); break; case Lifestyle.PerThread: //per thread removed from thread cache and OnContainerRelease called //and it can be released only in calling thread if (!ThreadOutgoingCache.ContainsKey(Thread.CurrentThread)) { throw new ContainerException("try to realease thread object from not configured thread"); } if (!ThreadOutgoingCache[Thread.CurrentThread].ContainsKey(obj)) { throw new ContainerException("try to release thread object on not it's thread"); } ThreadOutgoingCache[Thread.CurrentThread].Remove(obj); DropObject(obj); break; case Lifestyle.Singleton: //singletons cannot be released - they will still alive return; } OutgoingCache.Remove(obj); } }
/// <summary> /// Вызыает очистку контейнера /// </summary> /// <remarks> /// <invariant>Очистка очищает внутрненнее состояние и кэши контейнера, регистрации компонент это не касается, компоненты остаются в прежней конфигурации</invariant> /// </remarks> public void CleanUp() { foreach (var objreg in OutgoingCache) { DropObject(objreg.Key); } foreach (var objreg in Pool) { foreach (var o in objreg.Value) { DropObject(o); } } OutgoingCache.Clear(); Pool.Clear(); }
/// <summary> /// Возвращает сервис указанного типа. (прямое указание типа) /// </summary> /// <param name="type"> Тип сервиса </param> /// <param name="ctorArguments"> Параметры для вызова конструктора, если не указано - будет использован конструктор по умолчанию. </param> /// <param name="name"> опциональное имя компонента, если указано - поиск будет производиться только среди с компонентов с указаным именем </param> /// <returns> Сервис указанного типа или <c>null</c> , если подходящий компонент не обнаружен </returns> /// <exception cref="ContainerException">При ошибках в конструировании объектов</exception> public object Get(Type type, string name = null, params object[] ctorArguments) { lock (this) { type = type ?? typeof(object); if (type.IsValueType) { throw new ArgumentException("type must be interface or reference type"); } var preresolved = PreResolveWithSubResolvers(type, name, ctorArguments); if (null != preresolved) { return(preresolved); } var component = FindComponent(type, name); if (null == component) { var postresolved = PostResolveWithSubResolvers(type, name, (object[])ctorArguments); if (postresolved != null) { return(postresolved); } if (ThrowErrorOnNotExistedComponent) { throw new ContainerException(string.Format("cannot find component for {0} {1}", type, name)); } return(null); } component.ActivationCount++; object result = null; switch (component.Lifestyle) { case Lifestyle.Default: goto case Lifestyle.Transient; case Lifestyle.Extension: if (null != component.Implementation) { result = component.Implementation; break; } result = CreateInstance(component, ctorArguments); if (component.CacheInstanceOfExtension) { component.Implementation = result; } break; case Lifestyle.Transient: result = CreateInstance(component, ctorArguments); break; case Lifestyle.Pooled: if (Pool.ContainsKey(component) && Pool[component].Count != 0) { result = Pool[component].Pop(); } else { result = CreateInstance(component, ctorArguments); } OutgoingCache[result] = component; break; case Lifestyle.PerThread: if (!ThreadOutgoingCache.ContainsKey(Thread.CurrentThread)) { ThreadOutgoingCache[Thread.CurrentThread] = new Dictionary <object, IComponentDefinition>(); } if (ThreadOutgoingCache[Thread.CurrentThread].ContainsValue(component)) { result = ThreadOutgoingCache[Thread.CurrentThread].First(x => Equals(x.Value, component)).Key; } else { result = CreateInstance(component, ctorArguments); ThreadOutgoingCache[Thread.CurrentThread][result] = component; } OutgoingCache[result] = component; break; case Lifestyle.Singleton: if (null == component.Implementation) { component.Implementation = CreateInstance(component, ctorArguments); if (null != component.LinkedSingletons) { foreach (var linkedSingleton in component.LinkedSingletons) { if (null == linkedSingleton.Implementation) { linkedSingleton.Implementation = component.Implementation; } } } } result = component.Implementation; if (!OutgoingCache.ContainsKey(result)) { OutgoingCache[result] = component; } break; } var context = new ContainerContext { Component = component, Operation = ContainerOperation.AfterActivate, Object = result, }; ProcessExtensions(context); return(result); } }