/src/LinFu.IoC/FactoryStorage.cs

http://github.com/philiplaureano/LinFu · C# · 163 lines · 82 code · 29 blank · 52 comment · 23 complexity · 29544547eabb6141f8ec6bbe2f05f458 MD5 · raw file

  1. using System;
  2. using LinFu.IoC.Factories;
  3. using LinFu.IoC.Interfaces;
  4. namespace LinFu.IoC
  5. {
  6. /// <summary>
  7. /// Represents an <see cref="IFactoryStorage" /> instance that adds generics support to the
  8. /// <see cref="BaseFactoryStorage" /> implementation.
  9. /// </summary>
  10. public class FactoryStorage : BaseFactoryStorage
  11. {
  12. /// <summary>
  13. /// Determines whether or not an <see cref="IFactory" /> instance
  14. /// can be used to create the given service described by the <paramref name="serviceInfo" /> object.
  15. /// </summary>
  16. /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
  17. /// <returns><c>True</c> if the service can be created; otherwise, it will return <c>false</c>.</returns>
  18. public override bool ContainsFactory(IServiceInfo serviceInfo)
  19. {
  20. var serviceType = serviceInfo.ServiceType;
  21. var serviceName = serviceInfo.ServiceName;
  22. // Use the default implementation for
  23. // non-generic types
  24. if (!serviceType.IsGenericType && !serviceType.IsGenericTypeDefinition)
  25. return base.ContainsFactory(serviceInfo);
  26. // If the service type is a generic type, determine
  27. // if the service type can be created by a
  28. // standard factory that can create an instance
  29. // of that generic type (e.g., IFactory<IGeneric<T>>
  30. var result = base.ContainsFactory(serviceInfo);
  31. // Immediately return a positive match, if possible
  32. if (result)
  33. return true;
  34. if (!serviceType.IsGenericType || serviceType.IsGenericTypeDefinition)
  35. return false;
  36. // Determine the base type definition
  37. var baseDefinition = serviceType.GetGenericTypeDefinition();
  38. // Check if there are any generic factories that can create
  39. // the entire family of services whose type definitions
  40. // match the base type
  41. var genericServiceInfo = new ServiceInfo(serviceName, baseDefinition, serviceInfo.ArgumentTypes);
  42. result = base.ContainsFactory(genericServiceInfo);
  43. if (result)
  44. return true;
  45. if (baseDefinition == typeof(IFactory<>))
  46. {
  47. var typeArguments = serviceType.GetGenericArguments();
  48. var actualServiceType = typeArguments[0];
  49. var actualServiceInfo = new ServiceInfo(serviceName, actualServiceType, serviceInfo.ArgumentTypes);
  50. return base.ContainsFactory(actualServiceInfo);
  51. }
  52. return false;
  53. }
  54. /// <summary>
  55. /// Obtains the <see cref="IFactory" /> instance that can instantiate the
  56. /// service described by the <paramref name="serviceInfo" /> object instance.
  57. /// </summary>
  58. /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
  59. /// <returns>A <see cref="IFactory" /> instance if the service can be instantiated; otherwise, it will return <c>false</c>.</returns>
  60. public override IFactory GetFactory(IServiceInfo serviceInfo)
  61. {
  62. // Attempt to create the service type using
  63. // the strongly-typed arguments
  64. var factory = base.GetFactory(serviceInfo);
  65. var serviceType = serviceInfo.ServiceType;
  66. var serviceName = serviceInfo.ServiceName;
  67. // Use the default factory for this service type if no other factory exists
  68. factory = GetDefaultFactory(serviceName, serviceType, factory);
  69. // Attempt to create the service type using
  70. // the generic factories, if possible
  71. if (factory != null || !serviceType.IsGenericType)
  72. return factory;
  73. var definitionType = serviceType.GetGenericTypeDefinition();
  74. var genericServiceInfo = new ServiceInfo(serviceName, definitionType, serviceInfo.ArgumentTypes);
  75. // Find the generic factory that can specifically handle the given argument types
  76. var containsGenericFactory = base.ContainsFactory(genericServiceInfo);
  77. if (containsGenericFactory)
  78. return base.GetFactory(genericServiceInfo);
  79. // Use the default generic factory if we can't match the given arguments
  80. var defaultGenericServiceInfo = new ServiceInfo(serviceName, definitionType);
  81. if (base.ContainsFactory(defaultGenericServiceInfo))
  82. return base.GetFactory(defaultGenericServiceInfo);
  83. if (definitionType != typeof(IFactory<>))
  84. return factory;
  85. var typeArguments = serviceType.GetGenericArguments();
  86. var actualServiceType = typeArguments[0];
  87. factory = GetGenericFactory(serviceInfo, factory, serviceName, actualServiceType);
  88. return factory;
  89. }
  90. /// <summary>
  91. /// Gets the default factory for a particular service type if no other factory instance can be found.
  92. /// </summary>
  93. /// <param name="serviceName">The name of the service.</param>
  94. /// <param name="serviceType">The service type.</param>
  95. /// <param name="factory">
  96. /// The original factory instance that was supposed to be created in order to instantiate the service
  97. /// instance.
  98. /// </param>
  99. /// <returns>The actual factory instance that will be used to create the service instance.</returns>
  100. private IFactory GetDefaultFactory(string serviceName, Type serviceType, IFactory factory)
  101. {
  102. var defaultNamedServiceInfo = new ServiceInfo(serviceName, serviceType);
  103. if (factory == null && base.ContainsFactory(defaultNamedServiceInfo))
  104. factory = base.GetFactory(defaultNamedServiceInfo);
  105. if (serviceType.IsGenericType)
  106. {
  107. var defaultServiceInfo = new ServiceInfo(string.Empty, serviceType);
  108. if (factory == null && base.ContainsFactory(defaultServiceInfo))
  109. factory = base.GetFactory(defaultServiceInfo);
  110. }
  111. return factory;
  112. }
  113. /// <summary>
  114. /// Gets the generic factory for a concrete service type.
  115. /// </summary>
  116. /// <param name="serviceInfo">The <see cref="IServiceInfo" /> object that describes the service to be created.</param>
  117. /// <param name="factory">The factory instance that will be used to create the service.</param>
  118. /// <param name="serviceName">The name of the service.</param>
  119. /// <param name="actualServiceType">The service type.</param>
  120. /// <returns>A factory instance that can create the generic type.</returns>
  121. private IFactory GetGenericFactory(IServiceInfo serviceInfo, IFactory factory, string serviceName,
  122. Type actualServiceType)
  123. {
  124. var info = new ServiceInfo(serviceName, actualServiceType, serviceInfo.ArgumentTypes);
  125. if (base.ContainsFactory(info))
  126. {
  127. var actualFactory = base.GetFactory(info);
  128. Func<IFactoryRequest, object> factoryMethod = request => actualFactory;
  129. factory = new FunctorFactory<IFactory>(factoryMethod);
  130. }
  131. return factory;
  132. }
  133. }
  134. }