StateFactory.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using Wayne.Lib.StateEngine.Generic;
  5. using System.Diagnostics;
  6. namespace Wayne.Lib.StateEngine
  7. {
  8. /// <summary>
  9. /// State factory with the Main object T
  10. /// </summary>
  11. /// <typeparam name="T"></typeparam>
  12. public class StateFactory<T> : IStateFactory2
  13. {
  14. private readonly Func<T> main;
  15. private readonly IServiceLocator serviceContainer;
  16. /// <summary>
  17. /// Constructor
  18. /// </summary>
  19. /// <param name="main"></param>
  20. /// <param name="serviceContainer"></param>
  21. public StateFactory(T main, IServiceLocator serviceContainer)
  22. {
  23. this.main = () => main;
  24. this.serviceContainer = serviceContainer;
  25. }
  26. /// <summary>
  27. /// Constructor
  28. /// </summary>
  29. /// <param name="mainFunc"></param>
  30. /// <param name="serviceContainer"></param>
  31. public StateFactory(Func<T> mainFunc, IServiceLocator serviceContainer)
  32. {
  33. this.main = mainFunc;
  34. this.serviceContainer = serviceContainer;
  35. }
  36. #region Implementation of IStateFactory
  37. /// <summary>
  38. /// Tries to create the requested state
  39. /// </summary>
  40. /// <param name="stateFactoryName"></param>
  41. /// <returns></returns>
  42. public State CreateState(string stateFactoryName)
  43. {
  44. throw new InvalidOperationException("Use CreateState with StateTypeContainer");
  45. }
  46. private State TryCreate(Type stateType)
  47. {
  48. var constructors = stateType.GetConstructors();
  49. var lastConstructor = constructors[constructors.Length - 1];
  50. var parameterInfos = lastConstructor.GetParameters();
  51. List<object> parameters = new List<object>();
  52. foreach (var parameterInfo in parameterInfos)
  53. {
  54. try
  55. {
  56. parameters.Add(serviceContainer.GetService(parameterInfo.ParameterType));
  57. }
  58. catch (ServiceContainerException ex)
  59. {
  60. Debug.WriteLine(string.Format("Creating state {0} because its dependency {1} could not be found in the container. Error message : {2}", stateType, parameterInfo.ParameterType, ex.Message));
  61. throw;
  62. }
  63. }
  64. var stateObject = lastConstructor.Invoke(parameters.ToArray());
  65. return stateObject as State;
  66. }
  67. /// <summary>
  68. /// Prepare a state with a Main object if it has got one.
  69. /// </summary>
  70. /// <param name="stateObject"></param>
  71. protected virtual void PrepareState(object stateObject)
  72. {
  73. IGenericState<T> genericClientState = stateObject as IGenericState<T>;
  74. if (genericClientState != null)
  75. genericClientState.WritableMain = main();
  76. }
  77. /// <summary>
  78. /// Name of the State Factory
  79. /// </summary>
  80. public string Name
  81. {
  82. get { return GetType().Name; }
  83. }
  84. /// <summary>
  85. /// Creates the given state using the supplied StateTypeContainer
  86. /// </summary>
  87. /// <param name="stateFactoryName"></param>
  88. /// <param name="stateTypeContainer"></param>
  89. /// <returns></returns>
  90. public State CreateState(string stateFactoryName, StateTypeContainer stateTypeContainer)
  91. {
  92. Type stateType;
  93. if (stateTypeContainer.TryGetStateType(stateFactoryName, out stateType))
  94. {
  95. //Check if Main is of same type as T.
  96. List<Type> ancestry = new List<Type>();
  97. var mainObjectValue = main();
  98. Type type = mainObjectValue.GetType();
  99. do
  100. {
  101. ancestry.Add(type);
  102. type = type.BaseType;
  103. } while (type != typeof(object));
  104. State state = TryCreate(stateType);
  105. foreach (Type t in ancestry)
  106. {
  107. Type genericType = typeof(IGenericState<>);
  108. Type actualType = genericType.MakeGenericType(t);
  109. if (actualType.IsInstanceOfType(state))
  110. {
  111. PropertyInfo propertyInfo = actualType.GetProperty("WritableMain");
  112. propertyInfo.SetValue(state, mainObjectValue, new object[] { });
  113. }
  114. }
  115. return state;
  116. }
  117. return null;
  118. }
  119. #endregion
  120. }
  121. }