comparison Implab/ServiceLocator.cs @ 86:b33832ab0262 v2

ServiceLocator: added a cleanup callback to the service registration method
author cin
date Mon, 06 Oct 2014 03:41:17 +0400
parents 48763f3b5db8
children 79badb3ed195
comparison
equal deleted inserted replaced
85:abe260860bd6 86:b33832ab0262
1 using System; 1 using System;
2 using System.Collections.Generic; 2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Diagnostics;
6 3
7 namespace Implab { 4 namespace Implab {
8 /// <summary> 5 /// <summary>
9 /// Коллекция сервисов, позволяет регистрировать и получать сервисы. 6 /// Коллекция сервисов, позволяет регистрировать и получать сервисы.
10 /// </summary> 7 /// </summary>
11 public class ServiceLocator: Component, IServiceLocator, IServiceProvider { 8 public class ServiceLocator: Component, IServiceLocator, IServiceProvider {
12 // запись об сервисе 9 // запись о сервисе
13 struct ServiceEntry { 10 struct ServiceEntry : IDisposable {
14 public object service; // сервис 11 public object service; // сервис
15 public bool shared; // признак того, что сервис НЕ нужно освобождать 12 public bool shared; // признак того, что сервис НЕ нужно освобождать
16 public Func<object> activator; // активатор сервиса при первом обращении 13 public Func<object> activator; // активатор сервиса при первом обращении
14 public Action<object> cleanup; // функция для очистки сервиса
17 public List<Type> associated; // ссылки на текущую запись 15 public List<Type> associated; // ссылки на текущую запись
18 public Type origin; // ссылка на оригинальную запись о сервисе 16 public Type origin; // ссылка на оригинальную запись о сервисе
17
18 #region IDisposable implementation
19
20 public void Dispose() {
21 if (shared)
22 return;
23 if (cleanup != null)
24 cleanup(service);
25 else {
26 var d = service as IDisposable;
27 if (d != null)
28 d.Dispose();
29 }
30 }
31
32 #endregion
19 } 33 }
20 34
21 // словарь существующих сервисов 35 // словарь существующих сервисов
22 readonly Dictionary<Type, ServiceEntry> m_services = new Dictionary<Type,ServiceEntry>(); 36 readonly Dictionary<Type, ServiceEntry> m_services = new Dictionary<Type,ServiceEntry>();
23 37
70 /// </summary> 84 /// </summary>
71 /// <returns><c>true</c>, если сервис был найден, <c>false</c> в противном случае..</returns> 85 /// <returns><c>true</c>, если сервис был найден, <c>false</c> в противном случае..</returns>
72 /// <param name="serviceType">Тип запрашиваемого сервиса.</param> 86 /// <param name="serviceType">Тип запрашиваемого сервиса.</param>
73 /// <param name="service">Искомый сервис.</param> 87 /// <param name="service">Искомый сервис.</param>
74 public virtual bool TryGetService(Type serviceType, out object service) { 88 public virtual bool TryGetService(Type serviceType, out object service) {
75 if (serviceType == null) 89 Safe.ArgumentNotNull(serviceType, "serviceType");
76 throw new ArgumentNullException("serviceType");
77 AssertNotDisposed(); 90 AssertNotDisposed();
78 91
79 ServiceEntry se; 92 ServiceEntry se;
80 if (!m_services.TryGetValue(serviceType, out se)) { 93 if (!m_services.TryGetValue(serviceType, out se)) {
81 // ищем ближайщий объект, реализующий нужный сервис 94 // ищем ближайщий объект, реализующий нужный сервис
149 /// <summary> 162 /// <summary>
150 /// Регистрирует фабрику для активации сервиса по первому требованию. 163 /// Регистрирует фабрику для активации сервиса по первому требованию.
151 /// </summary> 164 /// </summary>
152 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam> 165 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
153 /// <param name="activator">Фабрика для создания/получения объекта, предоставляющего сервис.</param> 166 /// <param name="activator">Фабрика для создания/получения объекта, предоставляющего сервис.</param>
167 /// <param name = "cleanup">Метод для освобождения экземпляра сервиса, будет вызыван при освобождении сервис-локатора.</param>
154 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception> 168 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
155 /// <remarks>При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены.</remarks> 169 /// <remarks>При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены.</remarks>
156 public void Register<T>(Func<T> activator) { 170 public void Register<T>(Func<T> activator, Action<T> cleanup) {
157 if (activator == null) 171 Safe.ArgumentNotNull(activator, "activator");
158 throw new ArgumentNullException("activator");
159 172
160 AssertNotDisposed(); 173 AssertNotDisposed();
161 174
162 Unregister(typeof(T)); 175 Unregister(typeof(T));
163 176
164 m_services[typeof(T)] = new ServiceEntry { 177 m_services[typeof(T)] = new ServiceEntry {
165 activator = () => activator() as object 178 activator = () => activator(),
179 cleanup = instance => cleanup((T)instance)
166 }; 180 };
181 }
182
183 public void Register<T>(Func<T> activator) {
184 Register(activator, null);
167 } 185 }
168 186
169 /// <summary> 187 /// <summary>
170 /// Регистрирует объект, предоставляющий сервис. 188 /// Регистрирует объект, предоставляющий сервис.
171 /// </summary> 189 /// </summary>
183 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam> 201 /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
184 /// <param name="service">Объект, предоставляющий сервис.</param> 202 /// <param name="service">Объект, предоставляющий сервис.</param>
185 /// <param name="shared">Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать.</param> 203 /// <param name="shared">Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать.</param>
186 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception> 204 /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
187 public void Register<T>(T service, bool shared) { 205 public void Register<T>(T service, bool shared) {
188 if (service == null) 206 Safe.ArgumentNotNull(service, "service");
189 throw new ArgumentNullException("service");
190 207
191 AssertNotDisposed(); 208 AssertNotDisposed();
192 209
193 Unregister(typeof(T)); 210 Unregister(typeof(T));
194 211
195 m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared }; 212 m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared };
196 } 213 }
197 214
198 public void Unregister(Type serviceType) { 215 public void Unregister(Type serviceType) {
199 if (serviceType == null) 216 Safe.ArgumentNotNull(serviceType, "serviceType");
200 throw new ArgumentNullException("serviceType");
201 217
202 AssertNotDisposed(); 218 AssertNotDisposed();
203 219
204 ServiceEntry se; 220 ServiceEntry se;
205 if (m_services.TryGetValue(serviceType, out se)) { 221 if (m_services.TryGetValue(serviceType, out se)) {
221 /// <param name="disposing">Призанак того, что нужно освободить ресурсы.</param> 237 /// <param name="disposing">Призанак того, что нужно освободить ресурсы.</param>
222 protected override void Dispose(bool disposing) { 238 protected override void Dispose(bool disposing) {
223 if (disposing) { 239 if (disposing) {
224 240
225 foreach (var entry in m_services.Values) 241 foreach (var entry in m_services.Values)
226 if (!entry.shared && entry.service is IDisposable) 242 entry.Dispose();
227 ((IDisposable)entry.service).Dispose();
228 243
229 } 244 }
230 base.Dispose(disposing); 245 base.Dispose(disposing);
231 } 246 }
232 } 247 }