ServiceContainer.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. namespace Wayne.Lib
  6. {
  7. class ServiceContainer : IServiceContainer
  8. {
  9. private readonly IServiceLocator parentServiceLocator;
  10. private readonly Dictionary<ServiceKey, object> services;
  11. private bool disposed;
  12. private List<Func<Type, object>> resolvers = new List<Func<Type, object>>();
  13. public ServiceContainer()
  14. : this(null)
  15. {
  16. }
  17. public ServiceContainer(IServiceLocator parentServiceLocator)
  18. {
  19. services = new Dictionary<ServiceKey, object>();
  20. this.parentServiceLocator = parentServiceLocator;
  21. }
  22. public void RegisterResolver(Func<Type, object> requestedType)
  23. {
  24. resolvers.Add(requestedType);
  25. }
  26. public void RegisterService<TServiceImplementation>()
  27. {
  28. AssertContainerIsNotDisposed();
  29. var instance = (TServiceImplementation)TryCreate(typeof(TServiceImplementation));
  30. RegisterService(instance);
  31. }
  32. public void RegisterService<TServiceImplementation>(string serviceId)
  33. {
  34. AssertContainerIsNotDisposed();
  35. var instance = (TServiceImplementation)TryCreate(typeof(TServiceImplementation), serviceId);
  36. RegisterService(instance, serviceId);
  37. }
  38. public void RegisterService<TServiceContract>(TServiceContract serviceInstance)
  39. {
  40. RegisterService(serviceInstance, string.Empty);
  41. }
  42. public void RegisterService<TServiceContract>(TServiceContract serviceInstance, string serviceId)
  43. {
  44. AssertContainerIsNotDisposed();
  45. services[new ServiceKey(typeof(TServiceContract), serviceId)] = serviceInstance;
  46. }
  47. public void RegisterService<TServiceContract>(ObjectConstructor<IServiceLocator, TServiceContract> constructorMethod)
  48. {
  49. AssertContainerIsNotDisposed();
  50. var serviceInstance = constructorMethod.Invoke(this);
  51. services[new ServiceKey(typeof(TServiceContract))] = serviceInstance;
  52. }
  53. public void RegisterService<TServiceContract>(ObjectConstructor<IServiceLocator, TServiceContract> constructorMethod, string serviceId)
  54. {
  55. AssertContainerIsNotDisposed();
  56. var serviceInstance = constructorMethod.Invoke(this);
  57. services[new ServiceKey(typeof(TServiceContract), serviceId)] = serviceInstance;
  58. }
  59. public void RegisterService<TServiceContract, TServiceImplementation>()
  60. where TServiceImplementation : TServiceContract
  61. where TServiceContract : class
  62. {
  63. AssertContainerIsNotDisposed();
  64. var instance = (TServiceImplementation)TryCreate(typeof(TServiceImplementation));
  65. if ((object)instance == null) //Cast to object to get rid of warning
  66. throw new ServiceContainerException(typeof(TServiceImplementation), "Could not create implementation");
  67. RegisterService<TServiceContract>(instance);
  68. }
  69. public void RegisterService<TServiceContract, TServiceImplementation>(string serviceId)
  70. where TServiceImplementation : TServiceContract
  71. where TServiceContract : class
  72. {
  73. AssertContainerIsNotDisposed();
  74. var instance = (TServiceImplementation)TryCreate(typeof(TServiceImplementation), serviceId);
  75. if ((object)instance == null) //Cast to object to get rid of warning
  76. throw new ServiceContainerException(typeof(TServiceImplementation), "Could not create implementation");
  77. RegisterService<TServiceContract>(instance, serviceId);
  78. }
  79. public TServiceContract GetService<TServiceContract>()
  80. {
  81. return (TServiceContract)GetService(typeof(TServiceContract));
  82. }
  83. public TServiceContract GetService<TServiceContract>(string serviceId)
  84. {
  85. return (TServiceContract)GetService(typeof(TServiceContract), serviceId);
  86. }
  87. public object GetService(Type serviceType)
  88. {
  89. return GetService(serviceType, string.Empty);
  90. }
  91. public object GetService(Type serviceType, string serviceId)
  92. {
  93. AssertContainerIsNotDisposed();
  94. object service;
  95. if (services.TryGetValue(new ServiceKey(serviceType, serviceId), out service))
  96. return service;
  97. //Try resolvers
  98. service = resolvers
  99. .Select(x => x(serviceType))
  100. .FirstOrDefault(x => x != null);
  101. if (service != null)
  102. return service;
  103. //Try parent container
  104. if (parentServiceLocator != null)
  105. return parentServiceLocator.GetService(serviceType, serviceId);
  106. throw ServiceContainerException.CreateNotFoundException(serviceType);
  107. }
  108. public TServiceContract GetServiceOrDefault<TServiceContract>(CreateDefaultService<TServiceContract> func, string serviceId)
  109. {
  110. AssertContainerIsNotDisposed();
  111. object service;
  112. Type serviceType = typeof(TServiceContract);
  113. var key = new ServiceKey(serviceType, serviceId);
  114. if (!services.TryGetValue(key, out service))
  115. {
  116. //Try resolvers
  117. service = resolvers
  118. .Select(x => x(serviceType))
  119. .FirstOrDefault(x => x != null);
  120. if (service != null)
  121. {
  122. return (TServiceContract)service;
  123. }
  124. if (parentServiceLocator != null)
  125. return parentServiceLocator.GetServiceOrDefault(func, serviceId);
  126. return func();
  127. }
  128. return (TServiceContract)service;
  129. }
  130. public TServiceContract GetServiceOrDefault<TServiceContract>(CreateDefaultService<TServiceContract> func)
  131. {
  132. return GetServiceOrDefault(func, string.Empty);
  133. }
  134. public T CreateInstance<T>(params object[] additionalObjects) where T : class
  135. {
  136. return (T)CreateInstance(typeof(T), additionalObjects);
  137. }
  138. public object CreateInstance(Type typeToInstantiate, params object[] additionalParameter)
  139. {
  140. AssertContainerIsNotDisposed();
  141. object result = TryCreate(typeToInstantiate, additionalParameter);
  142. if (result == null)
  143. throw new ServiceContainerException(typeToInstantiate, "Could not create object");
  144. return result;
  145. }
  146. public T CreateInstance<T>(string serviceId, params object[] additionalObjects) where T : class
  147. {
  148. return (T)CreateInstance(typeof(T), serviceId, additionalObjects);
  149. }
  150. public object CreateInstance(Type typeToInstantiate, string serviceId, params object[] additionalParameter)
  151. {
  152. AssertContainerIsNotDisposed();
  153. object result = TryCreate(typeToInstantiate, serviceId, additionalParameter);
  154. if (result == null)
  155. throw new ServiceContainerException(typeToInstantiate, "Could not create object");
  156. return result;
  157. }
  158. private void AssertContainerIsNotDisposed()
  159. {
  160. if (disposed)
  161. throw new ObjectDisposedException(GetType().Name);
  162. }
  163. public object TryGetService(Type serviceType)
  164. {
  165. return TryGetService(serviceType, string.Empty);
  166. }
  167. public object TryGetService(Type serviceType, string serviceId)
  168. {
  169. object service;
  170. if (serviceType == typeof(IServiceLocator) || serviceType == typeof(IServiceContainer))
  171. return this;
  172. if (!services.TryGetValue(new ServiceKey(serviceType, serviceId), out service))
  173. {
  174. //Try resolvers
  175. service = resolvers
  176. .Select(x => x(serviceType))
  177. .FirstOrDefault(x => x != null);
  178. if (service != null)
  179. {
  180. return service;
  181. }
  182. if (parentServiceLocator != null)
  183. return parentServiceLocator.TryGetService(serviceType, serviceId);
  184. return null;
  185. }
  186. return service;
  187. }
  188. public T TryGetService<T>()
  189. {
  190. return TryGetService<T>(string.Empty);
  191. }
  192. public T TryGetService<T>(string serviceId)
  193. {
  194. Type serviceType = typeof(T);
  195. object result;
  196. if (serviceType == typeof(IServiceLocator) || serviceType == typeof(IServiceContainer))
  197. result = this;
  198. else
  199. {
  200. if (!services.TryGetValue(new ServiceKey(serviceType, serviceId), out result))
  201. {
  202. //Try resolvers
  203. result= resolvers
  204. .Select(x => x(serviceType))
  205. .FirstOrDefault(x => x != null);
  206. if (result != null)
  207. {
  208. return (T) result;
  209. }
  210. if (parentServiceLocator != null)
  211. result = parentServiceLocator.TryGetService(serviceType, serviceId);
  212. }
  213. }
  214. return (T)result;
  215. }
  216. private object TryCreate(Type typeToCreate, params object[] additionalObjects)
  217. {
  218. return TryCreate(typeToCreate, string.Empty, additionalObjects);
  219. }
  220. private object TryCreate(Type typeToCreate, string serviceId, params object[] additionalObjects)
  221. {
  222. var constructors = typeToCreate.GetConstructors();
  223. Array.Reverse(constructors);
  224. List<object> parameters = new List<object>();
  225. ConstructorInfo foundConstructor = null;
  226. foreach (ConstructorInfo constructor in constructors)
  227. {
  228. var parameterInfos = constructor.GetParameters();
  229. parameters.Clear();
  230. foreach (var parameterInfo in parameterInfos)
  231. {
  232. var dependency = TryGetService(parameterInfo.ParameterType, serviceId);
  233. if (dependency != null)
  234. {
  235. parameters.Add(dependency);
  236. }
  237. else
  238. {
  239. int firstMatchingParameterObjectIndex = -1;
  240. for (int index = 0; index < additionalObjects.Length; index++)
  241. {
  242. object additionalObject = additionalObjects[index];
  243. if (parameterInfo.ParameterType.IsAssignableFrom(additionalObject.GetType()))
  244. {
  245. firstMatchingParameterObjectIndex = index;
  246. break;
  247. }
  248. }
  249. if (firstMatchingParameterObjectIndex >= 0)
  250. {
  251. parameters.Add(additionalObjects[firstMatchingParameterObjectIndex]);
  252. }
  253. }
  254. }
  255. if (parameters.Count == parameterInfos.Length)
  256. {
  257. foundConstructor = constructor;
  258. break;
  259. }
  260. }
  261. if (foundConstructor != null)
  262. {
  263. var stateObject = foundConstructor.Invoke(parameters.ToArray());
  264. return stateObject;
  265. }
  266. return null;
  267. }
  268. // Help struct used as key in the dictionary of the container
  269. private struct ServiceKey
  270. {
  271. private readonly Type _typeOfObject;
  272. private readonly string _id;
  273. public ServiceKey(Type typeOfObject, string id)
  274. {
  275. _typeOfObject = typeOfObject;
  276. _id = id;
  277. }
  278. public ServiceKey(Type typeOfObject)
  279. {
  280. _typeOfObject = typeOfObject;
  281. _id = string.Empty;
  282. }
  283. public override int GetHashCode()
  284. {
  285. int hash = 17;
  286. hash = hash * 31 + _typeOfObject.GetHashCode();
  287. hash = hash * 31 + _id.GetHashCode();
  288. return hash;
  289. }
  290. public override bool Equals(object obj)
  291. {
  292. return obj is ServiceKey && this == (ServiceKey)obj;
  293. }
  294. public static bool operator ==(ServiceKey s1, ServiceKey s2)
  295. {
  296. return (s1._typeOfObject == s2._typeOfObject) && (s1._id.Equals(s2._id, StringComparison.InvariantCulture));
  297. }
  298. public static bool operator !=(ServiceKey s1, ServiceKey s2)
  299. {
  300. return !(s1 == s2);
  301. }
  302. }
  303. #region Implementation of IDisposable
  304. ~ServiceContainer()
  305. {
  306. Dispose(false);
  307. }
  308. public void Dispose()
  309. {
  310. Dispose(true);
  311. GC.SuppressFinalize(this);
  312. }
  313. private void Dispose(bool disposing)
  314. {
  315. if (disposed) return;
  316. disposed = true;
  317. if (disposing)
  318. {
  319. foreach (var service in services.Values)
  320. {
  321. var disposable = service as IDisposable;
  322. if (disposable != null)
  323. {
  324. try
  325. {
  326. disposable.Dispose();
  327. }
  328. catch
  329. {
  330. //Ignore errors
  331. }
  332. }
  333. }
  334. services.Clear();
  335. }
  336. }
  337. #endregion
  338. }
  339. }