SimpleContainer.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. namespace OpenSEMI.Core.Container
  5. {
  6. public class w : IContainer
  7. {
  8. private readonly ConcurrentDictionary<Type, CachedTypeInfo> _serviceTypeLookup = new ConcurrentDictionary<Type, CachedTypeInfo>();
  9. private readonly ConcurrentDictionary<Type, object> _serviceInstanceLookup = new ConcurrentDictionary<Type, object>();
  10. private readonly ConcurrentDictionary<Type, Action<object>> _serviceTypeCallbackLookup = new ConcurrentDictionary<Type, Action<object>>();
  11. #region IContainer Implementation
  12. public void Register<TService, TImplementation>() where TImplementation : TService
  13. {
  14. _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = typeof(TImplementation), IsSingleton = true };
  15. }
  16. public void Register<TService, TImplementation>(bool singleton = true) where TImplementation : TService
  17. {
  18. _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = typeof(TImplementation), IsSingleton = singleton };
  19. }
  20. public void Register<TService>(Type implementationType, bool singleton = true)
  21. {
  22. if (implementationType == null)
  23. throw new ArgumentNullException("implementationType cannot be null.");
  24. _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton };
  25. }
  26. public void Register<TService>(Type implementationType, Action<TService> callback, bool singleton = true)
  27. {
  28. if (implementationType == null)
  29. throw new ArgumentNullException("serviceType cannot be null.");
  30. _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton };
  31. if (callback != null)
  32. _serviceTypeCallbackLookup[typeof(TService)] = (x) => callback((TService)x);
  33. }
  34. public void Register(Type serviceType, Type implementationType, bool singleton = true)
  35. {
  36. if (serviceType == null)
  37. throw new ArgumentNullException("serviceType cannot be null.");
  38. if (implementationType == null)
  39. throw new ArgumentNullException("serviceType cannot be null.");
  40. if (!serviceType.IsAssignableFrom(implementationType))
  41. throw new ArgumentException(string.Format("Service could not be registered. {0} does not implement {1}.", implementationType.Name, serviceType.Name));
  42. _serviceTypeLookup[serviceType] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton };
  43. }
  44. public void Register<TService>(TService instance)
  45. {
  46. if (instance == null)
  47. throw new ArgumentNullException("instance cannot be null.");
  48. _serviceInstanceLookup[typeof(TService)] = instance;
  49. }
  50. public T Resolve<T>()
  51. {
  52. return (T)Resolve(typeof(T));
  53. }
  54. private object Resolve(Type type)
  55. {
  56. CachedTypeInfo containerType;
  57. object instance = null;
  58. // If the type isn't registered, register the type to itself.
  59. if (!_serviceTypeLookup.TryGetValue(type, out containerType))
  60. {
  61. Register(type, type);
  62. containerType = new CachedTypeInfo { Type = type, IsSingleton = true };
  63. }
  64. // TODO: Should it use the instance by default? I'd assume so initially.
  65. // Check if the service has an instance in the list of instances, if so, return it here.
  66. if (_serviceInstanceLookup.TryGetValue(type, out instance))
  67. return instance;
  68. var constructor = ConstructorCache.GetConstructor(containerType.Type);
  69. if (constructor != null)
  70. {
  71. // Get constructor parameters.
  72. var parameters = ParameterCache.GetParameters(constructor);
  73. var parameterObjects = new List<object>();
  74. foreach (var parameter in parameters)
  75. {
  76. parameterObjects.Add(Resolve(parameter.ParameterType));
  77. }
  78. var obj = Activator.CreateInstance(containerType.Type, parameterObjects.ToArray());
  79. Action<object> callback;
  80. if (_serviceTypeCallbackLookup.TryGetValue(type, out callback))
  81. callback(obj);
  82. if (containerType.IsSingleton)
  83. _serviceInstanceLookup[type] = obj;
  84. return obj;
  85. }
  86. else
  87. {
  88. // Return null rather than throw an exception for resolve failures.
  89. // This null will happen when there are 0 constructors for the supplied type.
  90. return null;
  91. }
  92. }
  93. public bool IsRegistered<TService>()
  94. {
  95. if (_serviceTypeLookup.ContainsKey(typeof(TService)) || _serviceInstanceLookup.ContainsKey(typeof(TService)))
  96. return true;
  97. return false;
  98. }
  99. #endregion
  100. #region IServiceProvider Implementation
  101. public object GetService(Type serviceType)
  102. {
  103. return Resolve(serviceType);
  104. }
  105. #endregion
  106. }
  107. }