IOCKit.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /****************************************************************************
  2. * Copyright (c) 2018 ~ 2022 liangxiegame UNDER MIT License
  3. *
  4. * http://qframework.io
  5. * https://github.com/liangxiegame/QFramework
  6. ****************************************************************************/
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Reflection;
  11. namespace QFramework
  12. {
  13. /// <summary>
  14. /// Used by the injection container to determine if a property or field should be injected.
  15. /// </summary>
  16. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
  17. public class InjectAttribute : Attribute
  18. {
  19. public InjectAttribute(string name)
  20. {
  21. Name = name;
  22. }
  23. public string Name { get; set; }
  24. public InjectAttribute()
  25. {
  26. }
  27. }
  28. public interface IQFrameworkContainer
  29. {
  30. /// <summary>
  31. /// Clears all type mappings and instances.
  32. /// </summary>
  33. void Clear();
  34. /// <summary>
  35. /// Injects registered types/mappings into an object
  36. /// </summary>
  37. /// <param name="obj"></param>
  38. void Inject(object obj);
  39. /// <summary>
  40. /// Injects everything that is registered at once
  41. /// </summary>
  42. void InjectAll();
  43. /// <summary>
  44. /// Register a type mapping
  45. /// </summary>
  46. /// <typeparam name="TSource">The base type.</typeparam>
  47. /// <typeparam name="TTarget">The concrete type</typeparam>
  48. void Register<TSource, TTarget>(string name = null);
  49. void RegisterRelation<TFor, TBase, TConcrete>();
  50. /// <summary>
  51. /// Register an instance of a type.
  52. /// </summary>
  53. /// <typeparam name="TBase"></typeparam>
  54. /// <param name="default"></param>
  55. /// <param name="injectNow"></param>
  56. /// <returns></returns>
  57. void RegisterInstance<TBase>(TBase @default, bool injectNow) where TBase : class;
  58. /// <summary>
  59. /// Register an instance of a type.
  60. /// </summary>
  61. /// <param name="type"></param>
  62. /// <param name="default"></param>
  63. /// <param name="injectNow"></param>
  64. /// <returns></returns>
  65. void RegisterInstance(Type type, object @default, bool injectNow);
  66. /// <summary>
  67. /// Register a named instance
  68. /// </summary>
  69. /// <param name="baseType">The type to register the instance for.</param>
  70. /// <param name="name">The name for the instance to be resolved.</param>
  71. /// <param name="instance">The instance that will be resolved be the name</param>
  72. /// <param name="injectNow">Perform the injection immediately</param>
  73. void RegisterInstance(Type baseType, object instance = null, string name = null, bool injectNow = true);
  74. void RegisterInstance<TBase>(TBase instance, string name, bool injectNow = true) where TBase : class;
  75. void RegisterInstance<TBase>(TBase instance) where TBase : class;
  76. /// <summary>
  77. /// If an instance of T exist then it will return that instance otherwise it will create a new one based off mappings.
  78. /// </summary>
  79. /// <typeparam name="T">The type of instance to resolve</typeparam>
  80. /// <returns>The/An instance of 'instanceType'</returns>
  81. T Resolve<T>(string name = null, bool requireInstance = false, params object[] args) where T : class;
  82. TBase ResolveRelation<TBase>(Type tfor, params object[] arg);
  83. TBase ResolveRelation<TFor, TBase>(params object[] arg);
  84. /// <summary>
  85. /// Resolves all instances of TType or subclasses of TType. Either named or not.
  86. /// </summary>
  87. /// <typeparam name="TType">The Type to resolve</typeparam>
  88. /// <returns>List of objects.</returns>
  89. IEnumerable<TType> ResolveAll<TType>();
  90. //IEnumerable<object> ResolveAll(Type type);
  91. void Register(Type source, Type target, string name = null);
  92. /// <summary>
  93. /// Resolves all instances of TType or subclasses of TType. Either named or not.
  94. /// </summary>
  95. /// <typeparam name="TType">The Type to resolve</typeparam>
  96. /// <returns>List of objects.</returns>
  97. IEnumerable<object> ResolveAll(Type type);
  98. TypeMappingCollection Mappings { get; set; }
  99. TypeInstanceCollection Instances { get; set; }
  100. TypeRelationCollection RelationshipMappings { get; set; }
  101. /// <summary>
  102. /// If an instance of instanceType exist then it will return that instance otherwise it will create a new one based off mappings.
  103. /// </summary>
  104. /// <param name="baseType">The type of instance to resolve</param>
  105. /// <param name="name">The type of instance to resolve</param>
  106. /// <param name="requireInstance">If true will return null if an instance isn't registered.</param>
  107. /// <returns>The/An instance of 'instanceType'</returns>
  108. object Resolve(Type baseType, string name = null, bool requireInstance = false,
  109. params object[] constructorArgs);
  110. object ResolveRelation(Type tfor, Type tbase, params object[] arg);
  111. void RegisterRelation(Type tfor, Type tbase, Type tconcrete);
  112. object CreateInstance(Type type, params object[] args);
  113. }
  114. /// <summary>
  115. /// A ViewModel Container and a factory for Controllers and commands.
  116. /// </summary>
  117. public class QFrameworkContainer : IQFrameworkContainer
  118. {
  119. private TypeInstanceCollection _instances;
  120. private TypeMappingCollection _mappings;
  121. public TypeMappingCollection Mappings
  122. {
  123. get { return _mappings ?? (_mappings = new TypeMappingCollection()); }
  124. set { _mappings = value; }
  125. }
  126. public TypeInstanceCollection Instances
  127. {
  128. get { return _instances ?? (_instances = new TypeInstanceCollection()); }
  129. set { _instances = value; }
  130. }
  131. public TypeRelationCollection RelationshipMappings
  132. {
  133. get { return _relationshipMappings; }
  134. set { _relationshipMappings = value; }
  135. }
  136. public IEnumerable<TType> ResolveAll<TType>()
  137. {
  138. foreach (var obj in ResolveAll(typeof(TType)))
  139. {
  140. yield return (TType) obj;
  141. }
  142. }
  143. /// <summary>
  144. /// Resolves all instances of TType or subclasses of TType. Either named or not.
  145. /// </summary>
  146. /// <typeparam name="TType">The Type to resolve</typeparam>
  147. /// <returns>List of objects.</returns>
  148. public IEnumerable<object> ResolveAll(Type type)
  149. {
  150. foreach (KeyValuePair<Tuple<Type, string>, object> kv in Instances)
  151. {
  152. if (kv.Key.Item1 == type && !string.IsNullOrEmpty(kv.Key.Item2))
  153. yield return kv.Value;
  154. }
  155. foreach (KeyValuePair<Tuple<Type, string>, Type> kv in Mappings)
  156. {
  157. if (!string.IsNullOrEmpty(kv.Key.Item2))
  158. {
  159. #if NETFX_CORE
  160. var condition = type.GetTypeInfo().IsSubclassOf(mapping.From);
  161. #else
  162. var condition = type.IsAssignableFrom(kv.Key.Item1);
  163. #endif
  164. if (condition)
  165. {
  166. var item = Activator.CreateInstance(kv.Value);
  167. Inject(item);
  168. yield return item;
  169. }
  170. }
  171. }
  172. }
  173. /// <summary>
  174. /// Clears all type-mappings and instances.
  175. /// </summary>
  176. public void Clear()
  177. {
  178. Instances.Clear();
  179. Mappings.Clear();
  180. RelationshipMappings.Clear();
  181. }
  182. /// <summary>
  183. /// Injects registered types/mappings into an object
  184. /// </summary>
  185. /// <param name="obj"></param>
  186. public void Inject(object obj)
  187. {
  188. if (obj == null) return;
  189. #if !NETFX_CORE
  190. var members = obj.GetType().GetMembers();
  191. #else
  192. var members = obj.GetType().GetTypeInfo().DeclaredMembers;
  193. #endif
  194. foreach (var memberInfo in members)
  195. {
  196. var injectAttribute =
  197. memberInfo.GetCustomAttributes(typeof(InjectAttribute), true).FirstOrDefault() as InjectAttribute;
  198. if (injectAttribute != null)
  199. {
  200. if (memberInfo is PropertyInfo)
  201. {
  202. var propertyInfo = memberInfo as PropertyInfo;
  203. propertyInfo.SetValue(obj, Resolve(propertyInfo.PropertyType, injectAttribute.Name), null);
  204. }
  205. else if (memberInfo is FieldInfo)
  206. {
  207. var fieldInfo = memberInfo as FieldInfo;
  208. fieldInfo.SetValue(obj, Resolve(fieldInfo.FieldType, injectAttribute.Name));
  209. }
  210. }
  211. }
  212. }
  213. /// <summary>
  214. /// Register a type mapping
  215. /// </summary>
  216. /// <typeparam name="TSource">The base type.</typeparam>
  217. /// <typeparam name="TTarget">The concrete type</typeparam>
  218. public void Register<TSource>(string name = null)
  219. {
  220. Mappings[typeof(TSource), name] = typeof(TSource);
  221. }
  222. /// <summary>
  223. /// Register a type mapping
  224. /// </summary>
  225. /// <typeparam name="TSource">The base type.</typeparam>
  226. /// <typeparam name="TTarget">The concrete type</typeparam>
  227. public void Register<TSource, TTarget>(string name = null)
  228. {
  229. Mappings[typeof(TSource), name] = typeof(TTarget);
  230. }
  231. public void Register(Type source, Type target, string name = null)
  232. {
  233. Mappings[source, name] = target;
  234. }
  235. /// <summary>
  236. /// Register a named instance
  237. /// </summary>
  238. /// <param name="baseType">The type to register the instance for.</param>
  239. /// <param name="instance">The instance that will be resolved be the name</param>
  240. /// <param name="injectNow">Perform the injection immediately</param>
  241. public void RegisterInstance(Type baseType, object instance = null, bool injectNow = true)
  242. {
  243. RegisterInstance(baseType, instance, null, injectNow);
  244. }
  245. /// <summary>
  246. /// Register a named instance
  247. /// </summary>
  248. /// <param name="baseType">The type to register the instance for.</param>
  249. /// <param name="name">The name for the instance to be resolved.</param>
  250. /// <param name="instance">The instance that will be resolved be the name</param>
  251. /// <param name="injectNow">Perform the injection immediately</param>
  252. public virtual void RegisterInstance(Type baseType, object instance = null, string name = null,
  253. bool injectNow = true)
  254. {
  255. Instances[baseType, name] = instance;
  256. if (injectNow)
  257. {
  258. Inject(instance);
  259. }
  260. }
  261. public void RegisterInstance<TBase>(TBase instance) where TBase : class
  262. {
  263. RegisterInstance<TBase>(instance, true);
  264. }
  265. public void RegisterInstance<TBase>(TBase instance, bool injectNow) where TBase : class
  266. {
  267. RegisterInstance<TBase>(instance, null, injectNow);
  268. }
  269. public void RegisterInstance<TBase>(TBase instance, string name, bool injectNow = true) where TBase : class
  270. {
  271. RegisterInstance(typeof(TBase), instance, name, injectNow);
  272. }
  273. /// <summary>
  274. /// If an instance of T exist then it will return that instance otherwise it will create a new one based off mappings.
  275. /// </summary>
  276. /// <typeparam name="T">The type of instance to resolve</typeparam>
  277. /// <returns>The/An instance of 'instanceType'</returns>
  278. public T Resolve<T>(string name = null, bool requireInstance = false, params object[] args) where T : class
  279. {
  280. return (T) Resolve(typeof(T), name, requireInstance, args);
  281. }
  282. /// <summary>
  283. /// If an instance of instanceType exist then it will return that instance otherwise it will create a new one based off mappings.
  284. /// </summary>
  285. /// <param name="baseType">The type of instance to resolve</param>
  286. /// <param name="name">The type of instance to resolve</param>
  287. /// <param name="requireInstance">If true will return null if an instance isn't registered.</param>
  288. /// <param name="constructorArgs">The arguments to pass to the constructor if any.</param>
  289. /// <returns>The/An instance of 'instanceType'</returns>
  290. public object Resolve(Type baseType, string name = null, bool requireInstance = false,
  291. params object[] constructorArgs)
  292. {
  293. // Look for an instance first
  294. var item = Instances[baseType, name];
  295. if (item != null)
  296. {
  297. return item;
  298. }
  299. if (requireInstance)
  300. return null;
  301. // Check if there is a mapping of the type
  302. var namedMapping = Mappings[baseType, name];
  303. if (namedMapping != null)
  304. {
  305. var obj = CreateInstance(namedMapping, constructorArgs);
  306. //Inject(obj);
  307. return obj;
  308. }
  309. return null;
  310. }
  311. public object CreateInstance(Type type, params object[] constructorArgs)
  312. {
  313. if (constructorArgs != null && constructorArgs.Length > 0)
  314. {
  315. //return Activator.CreateInstance(type,BindingFlags.Public | BindingFlags.Instance,Type.DefaultBinder, constructorArgs,CultureInfo.CurrentCulture);
  316. var obj2 = Activator.CreateInstance(type, constructorArgs);
  317. Inject(obj2);
  318. return obj2;
  319. }
  320. #if !NETFX_CORE
  321. ConstructorInfo[] constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
  322. #else
  323. ConstructorInfo[] constructor = type.GetTypeInfo().DeclaredConstructors.ToArray();
  324. #endif
  325. if (constructor.Length < 1)
  326. {
  327. var obj2 = Activator.CreateInstance(type);
  328. Inject(obj2);
  329. return obj2;
  330. }
  331. var maxParameters = constructor.First().GetParameters();
  332. foreach (var c in constructor)
  333. {
  334. var parameters = c.GetParameters();
  335. if (parameters.Length > maxParameters.Length)
  336. {
  337. maxParameters = parameters;
  338. }
  339. }
  340. var args = maxParameters.Select(p =>
  341. {
  342. if (p.ParameterType.IsArray)
  343. {
  344. return ResolveAll(p.ParameterType);
  345. }
  346. return Resolve(p.ParameterType) ?? Resolve(p.ParameterType, p.Name);
  347. }).ToArray();
  348. var obj = Activator.CreateInstance(type, args);
  349. Inject(obj);
  350. return obj;
  351. }
  352. public TBase ResolveRelation<TBase>(Type tfor, params object[] args)
  353. {
  354. try
  355. {
  356. return (TBase) ResolveRelation(tfor, typeof(TBase), args);
  357. }
  358. catch (InvalidCastException castIssue)
  359. {
  360. throw new Exception(
  361. string.Format("Resolve Relation couldn't cast to {0} from {1}", typeof(TBase).Name, tfor.Name),
  362. castIssue);
  363. }
  364. }
  365. public void InjectAll()
  366. {
  367. foreach (object instance in Instances.Values)
  368. {
  369. Inject(instance);
  370. }
  371. }
  372. private TypeRelationCollection _relationshipMappings = new TypeRelationCollection();
  373. public void RegisterRelation<TFor, TBase, TConcrete>()
  374. {
  375. RelationshipMappings[typeof(TFor), typeof(TBase)] = typeof(TConcrete);
  376. }
  377. public void RegisterRelation(Type tfor, Type tbase, Type tconcrete)
  378. {
  379. RelationshipMappings[tfor, tbase] = tconcrete;
  380. }
  381. public object ResolveRelation(Type tfor, Type tbase, params object[] args)
  382. {
  383. var concreteType = RelationshipMappings[tfor, tbase];
  384. if (concreteType == null)
  385. {
  386. return null;
  387. }
  388. var result = CreateInstance(concreteType, args);
  389. //Inject(result);
  390. return result;
  391. }
  392. public TBase ResolveRelation<TFor, TBase>(params object[] arg)
  393. {
  394. return (TBase) ResolveRelation(typeof(TFor), typeof(TBase), arg);
  395. }
  396. }
  397. // http://stackoverflow.com/questions/1171812/multi-key-dictionary-in-c
  398. public class Tuple<T1, T2> //FUCKING Unity: struct is not supported in Mono
  399. {
  400. public readonly T1 Item1;
  401. public readonly T2 Item2;
  402. public Tuple(T1 item1, T2 item2)
  403. {
  404. Item1 = item1;
  405. Item2 = item2;
  406. }
  407. public override bool Equals(Object obj)
  408. {
  409. Tuple<T1, T2> p = obj as Tuple<T1, T2>;
  410. if (obj == null) return false;
  411. if (Item1 == null)
  412. {
  413. if (p.Item1 != null) return false;
  414. }
  415. else
  416. {
  417. if (p.Item1 == null || !Item1.Equals(p.Item1)) return false;
  418. }
  419. if (Item2 == null)
  420. {
  421. if (p.Item2 != null) return false;
  422. }
  423. else
  424. {
  425. if (p.Item2 == null || !Item2.Equals(p.Item2)) return false;
  426. }
  427. return true;
  428. }
  429. public override int GetHashCode()
  430. {
  431. int hash = 0;
  432. if (Item1 != null)
  433. hash ^= Item1.GetHashCode();
  434. if (Item2 != null)
  435. hash ^= Item2.GetHashCode();
  436. return hash;
  437. }
  438. }
  439. // Kanglai: Using Dictionary rather than List!
  440. public class TypeMappingCollection : Dictionary<Tuple<Type, string>, Type>
  441. {
  442. public Type this[Type from, string name = null]
  443. {
  444. get
  445. {
  446. Tuple<Type, string> key = new Tuple<Type, string>(from, name);
  447. Type mapping = null;
  448. if (this.TryGetValue(key, out mapping))
  449. {
  450. return mapping;
  451. }
  452. return null;
  453. }
  454. set
  455. {
  456. Tuple<Type, string> key = new Tuple<Type, string>(from, name);
  457. this[key] = value;
  458. }
  459. }
  460. }
  461. public class TypeInstanceCollection : Dictionary<Tuple<Type, string>, object>
  462. {
  463. public object this[Type from, string name = null]
  464. {
  465. get
  466. {
  467. Tuple<Type, string> key = new Tuple<Type, string>(from, name);
  468. object mapping = null;
  469. if (this.TryGetValue(key, out mapping))
  470. {
  471. return mapping;
  472. }
  473. return null;
  474. }
  475. set
  476. {
  477. Tuple<Type, string> key = new Tuple<Type, string>(from, name);
  478. this[key] = value;
  479. }
  480. }
  481. }
  482. public class TypeRelationCollection : Dictionary<Tuple<Type, Type>, Type>
  483. {
  484. public Type this[Type from, Type to]
  485. {
  486. get
  487. {
  488. Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
  489. Type mapping = null;
  490. if (this.TryGetValue(key, out mapping))
  491. {
  492. return mapping;
  493. }
  494. return null;
  495. }
  496. set
  497. {
  498. Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
  499. this[key] = value;
  500. }
  501. }
  502. }
  503. }