PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/FishingPrototype/Assets/ThirdParty/Zenject/Source/Main/DiContainer.cs

https://gitlab.com/ChicK00o/JaneiousTests
C# | 1365 lines | 1038 code | 232 blank | 95 comment | 98 complexity | d86f451327f28cf04a8e879f11da772e MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using ModestTree;
  6. using ModestTree.Util;
  7. using Zenject.Internal;
  8. #if !NOT_UNITY3D
  9. using UnityEngine;
  10. #endif
  11. namespace Zenject
  12. {
  13. public delegate bool BindingCondition(InjectContext c);
  14. // Responsibilities:
  15. // - Expose methods to configure object graph via Bind() methods
  16. // - Build object graphs via Resolve() method
  17. public class DiContainer : IInstantiator, IResolver, IBinder
  18. {
  19. public const string DependencyRootIdentifier = "DependencyRoot";
  20. readonly Dictionary<BindingId, List<ProviderInfo>> _providers = new Dictionary<BindingId, List<ProviderInfo>>();
  21. readonly DiContainer _parentContainer;
  22. readonly Stack<LookupId> _resolvesInProgress = new Stack<LookupId>();
  23. readonly SingletonProviderCreator _singletonProviderCreator;
  24. readonly SingletonMarkRegistry _singletonMarkRegistry;
  25. readonly Queue<IBindingFinalizer> _currentBindings = new Queue<IBindingFinalizer>();
  26. readonly List<IBindingFinalizer> _processedBindings = new List<IBindingFinalizer>();
  27. bool _isValidating;
  28. bool _isInstalling;
  29. bool _hasDisplayedInstallWarning;
  30. public DiContainer(bool isValidating)
  31. {
  32. _isValidating = isValidating;
  33. _singletonMarkRegistry = new SingletonMarkRegistry();
  34. _singletonProviderCreator = new SingletonProviderCreator(this, _singletonMarkRegistry);
  35. // We can't simply call Bind<DiContainer>().FromInstance(this) here because
  36. // we don't want these bindings to be included in the Clone() below
  37. // So just directly add to the provider map instead
  38. var thisProvider = new InstanceProvider(typeof(DiContainer), this);
  39. var thisContracts = new Type[]
  40. {
  41. typeof(DiContainer), typeof(IBinder), typeof(IResolver), typeof(IInstantiator)
  42. };
  43. foreach (var contractType in thisContracts)
  44. {
  45. var infoList = new List<ProviderInfo>()
  46. {
  47. new ProviderInfo(thisProvider, null)
  48. };
  49. var bindingId = new BindingId(contractType, null);
  50. _providers.Add(bindingId, infoList);
  51. }
  52. }
  53. public DiContainer()
  54. : this(false)
  55. {
  56. }
  57. public DiContainer(DiContainer parentContainer, bool isValidating)
  58. : this(isValidating)
  59. {
  60. _parentContainer = parentContainer;
  61. if (parentContainer != null)
  62. {
  63. parentContainer.FlushBindings();
  64. #if !NOT_UNITY3D
  65. DefaultParent = parentContainer.DefaultParent;
  66. #endif
  67. foreach (var binding in parentContainer._processedBindings
  68. .Where(x => x.InheritInSubContainers))
  69. {
  70. _currentBindings.Enqueue(binding);
  71. }
  72. FlushBindings();
  73. }
  74. }
  75. public DiContainer(DiContainer parentContainer)
  76. : this(parentContainer, false)
  77. {
  78. }
  79. // When true, this will throw exceptions whenever we create new game objects
  80. // This is helpful when used in places like EditorWindowKernel where we can't
  81. // assume that there is a "scene" to place objects
  82. public bool AssertOnNewGameObjects
  83. {
  84. get;
  85. set;
  86. }
  87. public SingletonMarkRegistry SingletonMarkRegistry
  88. {
  89. get
  90. {
  91. return _singletonMarkRegistry;
  92. }
  93. }
  94. public SingletonProviderCreator SingletonProviderCreator
  95. {
  96. get
  97. {
  98. return _singletonProviderCreator;
  99. }
  100. }
  101. #if !NOT_UNITY3D
  102. public Transform DefaultParent
  103. {
  104. get;
  105. set;
  106. }
  107. #endif
  108. public DiContainer ParentContainer
  109. {
  110. get
  111. {
  112. return _parentContainer;
  113. }
  114. }
  115. public bool ChecksForCircularDependencies
  116. {
  117. get
  118. {
  119. #if ZEN_MULTITHREADING
  120. // When multithreading is supported we can't use a static field to track the lookup
  121. // TODO: We could look at the inject context though
  122. return false;
  123. #else
  124. return true;
  125. #endif
  126. }
  127. }
  128. // See comment in IBinder.cs for description
  129. public bool IsValidating
  130. {
  131. get
  132. {
  133. return _isValidating;
  134. }
  135. }
  136. // When this is true, it will log warnings when Resolve or Instantiate
  137. // methods are called
  138. // Used to ensure that Resolve and Instantiate methods are not called
  139. // during bind phase. This is important since Resolve and Instantiate
  140. // make use of the bindings, so if the bindings are not complete then
  141. // unexpected behaviour can occur
  142. public bool IsInstalling
  143. {
  144. get
  145. {
  146. return _isInstalling;
  147. }
  148. set
  149. {
  150. _isInstalling = value;
  151. }
  152. }
  153. public IEnumerable<BindingId> AllContracts
  154. {
  155. get
  156. {
  157. FlushBindings();
  158. return _providers.Keys;
  159. }
  160. }
  161. // DO not run this within Unity!
  162. // This is only really useful if you are not using any of the Unity bind methods such as
  163. // FromGameObject, FromPrefab, etc.
  164. // If you are using those, and you call this method, then it will have side effects like
  165. // creating game objects
  166. // Otherwise, it should be safe to call since all the fake instances will be limited to
  167. // within a cloned copy of the DiContainer and should not have any side effects
  168. public void Validate()
  169. {
  170. var container = CloneForValidate();
  171. Assert.That(container.IsValidating);
  172. // It's tempting here to iterate over all the BindingId's in _providers
  173. // and make sure they can be resolved but that fails once we start
  174. // using complex conditionals, so this is the best we can do
  175. container.ResolveDependencyRoots();
  176. container.ValidateIValidatables();
  177. }
  178. public List<object> ResolveDependencyRoots()
  179. {
  180. var context = new InjectContext(
  181. this, typeof(object), DependencyRootIdentifier);
  182. context.SourceType = InjectSources.Local;
  183. context.Optional = true;
  184. return ResolveAll(context).Cast<object>().ToList();
  185. }
  186. DiContainer CloneForValidate()
  187. {
  188. FlushBindings();
  189. DiContainer container;
  190. if (this.ParentContainer == null)
  191. {
  192. container = new DiContainer(null, true);
  193. }
  194. else
  195. {
  196. // Need to clone all parents too
  197. container = new DiContainer(
  198. this.ParentContainer.CloneForValidate(), true);
  199. }
  200. // Validating shouldn't have side effects, so assert if this occurs
  201. container.AssertOnNewGameObjects = true;
  202. foreach (var binding in _processedBindings)
  203. {
  204. container._currentBindings.Enqueue(binding);
  205. }
  206. container.FlushBindings();
  207. return container;
  208. }
  209. public void ValidateIValidatables()
  210. {
  211. Assert.That(IsValidating);
  212. foreach (var pair in _providers.ToList())
  213. {
  214. var bindingId = pair.Key;
  215. var providers = pair.Value;
  216. // Validate all IValidatable's
  217. List<ProviderInfo> validatableProviders;
  218. var injectContext = new InjectContext(
  219. this, bindingId.Type, bindingId.Identifier);
  220. if (bindingId.Type.DerivesFrom<IValidatable>())
  221. {
  222. validatableProviders = providers;
  223. }
  224. else
  225. {
  226. validatableProviders = providers
  227. .Where(x => x.Provider.GetInstanceType(injectContext)
  228. .DerivesFrom<IValidatable>()).ToList();
  229. }
  230. foreach (var provider in validatableProviders)
  231. {
  232. var validatable = (IValidatable)provider.Provider.GetInstance(injectContext);
  233. validatable.Validate();
  234. }
  235. }
  236. }
  237. public DiContainer CreateSubContainer()
  238. {
  239. return CreateSubContainer(_isValidating);
  240. }
  241. public DiContainer CreateSubContainer(bool isValidating)
  242. {
  243. return new DiContainer(this, isValidating);
  244. }
  245. public void RegisterProvider(
  246. BindingId bindingId, BindingCondition condition, IProvider provider)
  247. {
  248. var info = new ProviderInfo(provider, condition);
  249. if (_providers.ContainsKey(bindingId))
  250. {
  251. _providers[bindingId].Add(info);
  252. }
  253. else
  254. {
  255. _providers.Add(bindingId, new List<ProviderInfo> { info });
  256. }
  257. }
  258. // Wrap IEnumerable<> to avoid LINQ mistakes
  259. internal List<IProvider> GetAllProviderMatches(InjectContext context)
  260. {
  261. Assert.IsNotNull(context);
  262. return GetProviderMatchesInternal(context).Select(x => x.ProviderInfo.Provider).ToList();
  263. }
  264. // Be careful with this method since it is a coroutine
  265. IEnumerable<ProviderPair> GetProviderMatchesInternal(InjectContext context)
  266. {
  267. Assert.IsNotNull(context);
  268. return GetProvidersForContract(context.GetBindingId(), context.SourceType)
  269. .Where(x => x.ProviderInfo.Condition == null || x.ProviderInfo.Condition(context));
  270. }
  271. IEnumerable<ProviderPair> GetProvidersForContract(BindingId bindingId, InjectSources sourceType)
  272. {
  273. FlushBindings();
  274. switch (sourceType)
  275. {
  276. case InjectSources.Local:
  277. {
  278. return GetLocalProviders(bindingId).Select(x => new ProviderPair(x, this));
  279. }
  280. case InjectSources.Any:
  281. {
  282. var localPairs = GetLocalProviders(bindingId).Select(x => new ProviderPair(x, this));
  283. if (_parentContainer == null)
  284. {
  285. return localPairs;
  286. }
  287. return localPairs.Concat(
  288. _parentContainer.GetProvidersForContract(bindingId, InjectSources.Any));
  289. }
  290. case InjectSources.AnyParent:
  291. {
  292. if (_parentContainer == null)
  293. {
  294. return Enumerable.Empty<ProviderPair>();
  295. }
  296. return _parentContainer.GetProvidersForContract(bindingId, InjectSources.Any);
  297. }
  298. case InjectSources.Parent:
  299. {
  300. if (_parentContainer == null)
  301. {
  302. return Enumerable.Empty<ProviderPair>();
  303. }
  304. return _parentContainer.GetProvidersForContract(bindingId, InjectSources.Local);
  305. }
  306. }
  307. throw Assert.CreateException("Invalid source type");
  308. }
  309. List<ProviderInfo> GetLocalProviders(BindingId bindingId)
  310. {
  311. List<ProviderInfo> localProviders;
  312. if (_providers.TryGetValue(bindingId, out localProviders))
  313. {
  314. return localProviders;
  315. }
  316. // If we are asking for a List<int>, we should also match for any localProviders that are bound to the open generic type List<>
  317. // Currently it only matches one and not the other - not totally sure if this is better than returning both
  318. if (bindingId.Type.IsGenericType() && _providers.TryGetValue(new BindingId(bindingId.Type.GetGenericTypeDefinition(), bindingId.Identifier), out localProviders))
  319. {
  320. return localProviders;
  321. }
  322. return new List<ProviderInfo>();
  323. }
  324. // See comment in IResolver.cs for description of this method
  325. public IList ResolveAll(InjectContext context)
  326. {
  327. Assert.IsNotNull(context);
  328. // Note that different types can map to the same provider (eg. a base type to a concrete class and a concrete class to itself)
  329. FlushBindings();
  330. CheckForInstallWarning(context);
  331. var matches = GetProviderMatchesInternal(context).ToList();
  332. if (matches.Any())
  333. {
  334. var instances = matches.SelectMany(x => SafeGetInstances(x.ProviderInfo.Provider, context)).ToArray();
  335. if (IsValidating)
  336. {
  337. instances = instances.Select(x => x is ValidationMarker ? context.MemberType.GetDefaultValue() : x).ToArray();
  338. }
  339. return ReflectionUtil.CreateGenericList(context.MemberType, instances);
  340. }
  341. Assert.That(context.Optional,
  342. "Could not find required dependency with type '{0}' \nObject graph:\n {1}", context.MemberType.Name(), context.GetObjectGraphString());
  343. return ReflectionUtil.CreateGenericList(context.MemberType, new object[] {});
  344. }
  345. void CheckForInstallWarning(InjectContext context)
  346. {
  347. Assert.IsNotNull(context);
  348. #if DEBUG || UNITY_EDITOR
  349. if (!_isInstalling)
  350. {
  351. return;
  352. }
  353. if (_hasDisplayedInstallWarning)
  354. {
  355. return;
  356. }
  357. if (context == null)
  358. {
  359. // No way to tell whether this is ok or not so just assume ok
  360. return;
  361. }
  362. var rootContext = context.ParentContextsAndSelf.Last();
  363. if (rootContext.MemberType.DerivesFrom<IInstaller>())
  364. {
  365. // Resolving/instantiating/injecting installers is valid during install phase
  366. return;
  367. }
  368. #if !NOT_UNITY3D
  369. if (rootContext.MemberType.DerivesFrom<DecoratorInstaller>())
  370. {
  371. return;
  372. }
  373. #endif
  374. _hasDisplayedInstallWarning = true;
  375. // Feel free to comment this out if you are comfortable with this practice
  376. Log.Warn("Zenject Warning: It is bad practice to call Inject/Resolve/Instantiate before all the Installers have completed! This is important to ensure that all bindings have properly been installed in case they are needed when injecting/instantiating/resolving. Detected when operating on type '{0}'", rootContext.MemberType.Name());
  377. #endif
  378. }
  379. // See comment in IResolver.cs for description of this method
  380. public List<Type> ResolveTypeAll(InjectContext context)
  381. {
  382. Assert.IsNotNull(context);
  383. FlushBindings();
  384. CheckForInstallWarning(context);
  385. var providers = GetProviderMatchesInternal(context).ToList();
  386. if (providers.Count > 0 )
  387. {
  388. return providers.Select(x => x.ProviderInfo.Provider.GetInstanceType(context)).Where(x => x != null).ToList();
  389. }
  390. return new List<Type> {};
  391. }
  392. // Try looking up a single provider for a given context
  393. // Note that this method should not throw zenject exceptions
  394. internal ProviderLookupResult TryGetUniqueProvider(
  395. InjectContext context, out IProvider provider)
  396. {
  397. Assert.IsNotNull(context);
  398. // Note that different types can map to the same provider (eg. a base type to a concrete class and a concrete class to itself)
  399. var providers = GetProviderMatchesInternal(context).ToList();
  400. if (providers.IsEmpty())
  401. {
  402. provider = null;
  403. return ProviderLookupResult.None;
  404. }
  405. if (providers.Count > 1)
  406. {
  407. // If we find multiple providers and we are looking for just one, then
  408. // try to intelligently choose one from the list before giving up
  409. // First try picking the most 'local' dependencies
  410. // This will bias towards bindings for the lower level specific containers rather than the global high level container
  411. // This will, for example, allow you to just ask for a DiContainer dependency without needing to specify [Inject(Source = InjectSources.Local)]
  412. // (otherwise it would always match for a list of DiContainer's for all parent containers)
  413. var sortedProviders = providers.Select(x => new { Pair = x, Distance = GetContainerHeirarchyDistance(x.Container) }).OrderBy(x => x.Distance).ToList();
  414. sortedProviders.RemoveAll(x => x.Distance != sortedProviders[0].Distance);
  415. if (sortedProviders.Count == 1)
  416. {
  417. // We have one match that is the closest
  418. provider = sortedProviders[0].Pair.ProviderInfo.Provider;
  419. }
  420. else
  421. {
  422. // Try choosing the one with a condition before giving up and throwing an exception
  423. // This is nice because it allows us to bind a default and then override with conditions
  424. provider = sortedProviders.Where(x => x.Pair.ProviderInfo.Condition != null).Select(x => x.Pair.ProviderInfo.Provider).OnlyOrDefault();
  425. if (provider == null)
  426. {
  427. return ProviderLookupResult.Multiple;
  428. }
  429. }
  430. }
  431. else
  432. {
  433. provider = providers.Single().ProviderInfo.Provider;
  434. }
  435. Assert.IsNotNull(provider);
  436. return ProviderLookupResult.Success;
  437. }
  438. // See comment in IResolver.cs for description of this method
  439. public object Resolve(InjectContext context)
  440. {
  441. Assert.IsNotNull(context);
  442. IProvider provider;
  443. FlushBindings();
  444. CheckForInstallWarning(context);
  445. var result = TryGetUniqueProvider(context, out provider);
  446. Assert.That(result != ProviderLookupResult.Multiple,
  447. "Found multiple matches when only one was expected for type '{0}'{1}. \nObject graph:\n {2}",
  448. context.MemberType.Name(),
  449. (context.ObjectType == null ? "" : " while building object with type '{0}'".Fmt(context.ObjectType.Name())),
  450. context.GetObjectGraphString());
  451. if (result == ProviderLookupResult.None)
  452. {
  453. // If it's a generic list then try matching multiple instances to its generic type
  454. if (ReflectionUtil.IsGenericList(context.MemberType))
  455. {
  456. var subType = context.MemberType.GenericArguments().Single();
  457. var subContext = context.Clone();
  458. subContext.MemberType = subType;
  459. return ResolveAll(subContext);
  460. }
  461. if (context.Optional)
  462. {
  463. return context.FallBackValue;
  464. }
  465. throw Assert.CreateException("Unable to resolve type '{0}'{1}. \nObject graph:\n{2}",
  466. context.MemberType.Name() + (context.Identifier == null ? "" : " with ID '{0}'".Fmt(context.Identifier.ToString())),
  467. (context.ObjectType == null ? "" : " while building object with type '{0}'".Fmt(context.ObjectType.Name())),
  468. context.GetObjectGraphString());
  469. }
  470. Assert.That(result == ProviderLookupResult.Success);
  471. Assert.IsNotNull(provider);
  472. var instances = SafeGetInstances(provider, context);
  473. Assert.That(!instances.IsEmpty(), "Provider returned zero instances when one was expected!");
  474. Assert.That(instances.Count() == 1, "Provider returned multiple instances when one was expected!");
  475. return instances.First();
  476. }
  477. IEnumerable<object> SafeGetInstances(IProvider provider, InjectContext context)
  478. {
  479. Assert.IsNotNull(context);
  480. if (ChecksForCircularDependencies)
  481. {
  482. var lookupId = new LookupId(provider, context.GetBindingId());
  483. // Allow one before giving up so that you can do circular dependencies via postinject or fields
  484. Assert.That(_resolvesInProgress.Where(x => x.Equals(lookupId)).Count() <= 1,
  485. "Circular dependency detected! \nObject graph:\n {0}", context.GetObjectGraphString());
  486. _resolvesInProgress.Push(lookupId);
  487. try
  488. {
  489. return provider.GetAllInstances(context);
  490. }
  491. finally
  492. {
  493. Assert.That(_resolvesInProgress.Peek().Equals(lookupId));
  494. _resolvesInProgress.Pop();
  495. }
  496. }
  497. else
  498. {
  499. return provider.GetAllInstances(context);
  500. }
  501. }
  502. int GetContainerHeirarchyDistance(DiContainer container)
  503. {
  504. return GetContainerHeirarchyDistance(container, 0);
  505. }
  506. int GetContainerHeirarchyDistance(DiContainer container, int depth)
  507. {
  508. if (container == this)
  509. {
  510. return depth;
  511. }
  512. Assert.IsNotNull(_parentContainer);
  513. return _parentContainer.GetContainerHeirarchyDistance(container, depth + 1);
  514. }
  515. public IEnumerable<Type> GetDependencyContracts<TContract>()
  516. {
  517. return GetDependencyContracts(typeof(TContract));
  518. }
  519. public IEnumerable<Type> GetDependencyContracts(Type contract)
  520. {
  521. FlushBindings();
  522. foreach (var injectMember in TypeAnalyzer.GetInfo(contract).AllInjectables)
  523. {
  524. yield return injectMember.MemberType;
  525. }
  526. }
  527. public T InstantiateExplicit<T>(List<TypeValuePair> extraArgs)
  528. {
  529. return (T)InstantiateExplicit(typeof(T), extraArgs);
  530. }
  531. public object InstantiateExplicit(Type concreteType, List<TypeValuePair> extraArgs)
  532. {
  533. bool autoInject = true;
  534. return InstantiateExplicit(
  535. concreteType,
  536. autoInject,
  537. new InjectArgs()
  538. {
  539. ExtraArgs = extraArgs,
  540. Context = new InjectContext(this, concreteType, null),
  541. ConcreteIdentifier = null,
  542. UseAllArgs = true,
  543. });
  544. }
  545. // See comment in IInstantiator.cs for description of this method
  546. public object InstantiateExplicit(Type concreteType, bool autoInject, InjectArgs args)
  547. {
  548. #if PROFILING_ENABLED
  549. using (ProfileBlock.Start("Zenject.Instantiate({0})", concreteType))
  550. #endif
  551. {
  552. return InstantiateInternal(concreteType, autoInject, args);
  553. }
  554. }
  555. public static bool CanCreateOrInjectDuringValidation(Type type)
  556. {
  557. // During validation, do not instantiate or inject anything except for
  558. // Installers, IValidatable's, or types marked with attribute ZenjectAllowDuringValidation
  559. // You would typically use ZenjectAllowDuringValidation attribute for data that you
  560. // inject into factories
  561. return type.DerivesFrom<IInstaller>()
  562. || type.DerivesFrom<IValidatable>()
  563. #if !NOT_UNITY3D
  564. || type.DerivesFrom<Context>()
  565. || type.DerivesFrom<DecoratorInstaller>()
  566. #endif
  567. #if !(UNITY_WSA && ENABLE_DOTNET)
  568. || type.HasAttribute<ZenjectAllowDuringValidationAttribute>()
  569. #endif
  570. ;
  571. }
  572. object InstantiateInternal(Type concreteType, bool autoInject, InjectArgs args)
  573. {
  574. #if !NOT_UNITY3D
  575. Assert.That(!concreteType.DerivesFrom<UnityEngine.Component>(),
  576. "Error occurred while instantiating object of type '{0}'. Instantiator should not be used to create new mono behaviours. Must use InstantiatePrefabForComponent, InstantiatePrefab, or InstantiateComponent.", concreteType.Name());
  577. #endif
  578. Assert.That(!concreteType.IsAbstract(), "Expected type 'type' to be non-abstract", concreteType);
  579. FlushBindings();
  580. CheckForInstallWarning(args.Context);
  581. var typeInfo = TypeAnalyzer.GetInfo(concreteType);
  582. object newObj;
  583. #if !NOT_UNITY3D
  584. if (concreteType.DerivesFrom<ScriptableObject>())
  585. {
  586. Assert.That( typeInfo.ConstructorInjectables.IsEmpty(),
  587. "Found constructor parameters on ScriptableObject type '{0}'. This is not allowed. Use an [Inject] method or fields instead.");
  588. if (!IsValidating || CanCreateOrInjectDuringValidation(concreteType))
  589. {
  590. newObj = ScriptableObject.CreateInstance(concreteType);
  591. }
  592. else
  593. {
  594. newObj = new ValidationMarker(concreteType);
  595. }
  596. }
  597. else
  598. #endif
  599. {
  600. Assert.IsNotNull(typeInfo.InjectConstructor,
  601. "More than one (or zero) constructors found for type '{0}' when creating dependencies. Use one [Inject] attribute to specify which to use.", concreteType);
  602. // Make a copy since we remove from it below
  603. var paramValues = new List<object>();
  604. foreach (var injectInfo in typeInfo.ConstructorInjectables)
  605. {
  606. object value;
  607. if (!InjectUtil.PopValueWithType(
  608. args.ExtraArgs, injectInfo.MemberType, out value))
  609. {
  610. value = Resolve(injectInfo.CreateInjectContext(
  611. this, args.Context, null, args.ConcreteIdentifier));
  612. }
  613. if (value is ValidationMarker)
  614. {
  615. Assert.That(IsValidating);
  616. paramValues.Add(injectInfo.MemberType.GetDefaultValue());
  617. }
  618. else
  619. {
  620. paramValues.Add(value);
  621. }
  622. }
  623. if (!IsValidating || CanCreateOrInjectDuringValidation(concreteType))
  624. {
  625. //Log.Debug("Zenject: Instantiating type '{0}'", concreteType.Name());
  626. try
  627. {
  628. #if PROFILING_ENABLED
  629. using (ProfileBlock.Start("{0}.{0}()", concreteType))
  630. #endif
  631. {
  632. newObj = typeInfo.InjectConstructor.Invoke(paramValues.ToArray());
  633. }
  634. }
  635. catch (Exception e)
  636. {
  637. throw Assert.CreateException(
  638. e, "Error occurred while instantiating object with type '{0}'", concreteType.Name());
  639. }
  640. }
  641. else
  642. {
  643. newObj = new ValidationMarker(concreteType);
  644. }
  645. }
  646. if (autoInject)
  647. {
  648. InjectExplicit(newObj, concreteType, args);
  649. }
  650. else if (args.UseAllArgs && !args.ExtraArgs.IsEmpty())
  651. {
  652. throw Assert.CreateException(
  653. "Passed unnecessary parameters when injecting into type '{0}'. \nExtra Parameters: {1}\nObject graph:\n{2}",
  654. newObj.GetType().Name(), String.Join(",", args.ExtraArgs.Select(x => x.Type.Name()).ToArray()), args.Context.GetObjectGraphString());
  655. }
  656. return newObj;
  657. }
  658. public void InjectExplicit(object injectable, List<TypeValuePair> extraArgs)
  659. {
  660. Type injectableType;
  661. if (injectable is ValidationMarker)
  662. {
  663. injectableType = ((ValidationMarker)injectable).MarkedType;
  664. }
  665. else
  666. {
  667. injectableType = injectable.GetType();
  668. }
  669. InjectExplicit(
  670. injectable,
  671. injectableType,
  672. new InjectArgs()
  673. {
  674. ExtraArgs = extraArgs,
  675. UseAllArgs = true,
  676. Context = new InjectContext(this, injectableType, null),
  677. ConcreteIdentifier = null,
  678. });
  679. }
  680. // See comment in IResolver.cs for description of this method
  681. public void InjectExplicit(
  682. object injectable, Type injectableType, InjectArgs args)
  683. {
  684. Assert.That(injectable != null);
  685. // Installers are the only things that we instantiate/inject on during validation
  686. bool isDryRun = IsValidating && !CanCreateOrInjectDuringValidation(injectableType);
  687. if (!isDryRun)
  688. {
  689. Assert.IsEqual(injectable.GetType(), injectableType);
  690. }
  691. #if !NOT_UNITY3D
  692. Assert.That(injectableType != typeof(GameObject),
  693. "Use InjectGameObject to Inject game objects instead of Inject method");
  694. #endif
  695. FlushBindings();
  696. CheckForInstallWarning(args.Context);
  697. var typeInfo = TypeAnalyzer.GetInfo(injectableType);
  698. foreach (var injectInfo in typeInfo.FieldInjectables.Concat(
  699. typeInfo.PropertyInjectables))
  700. {
  701. object value;
  702. if (InjectUtil.PopValueWithType(args.ExtraArgs, injectInfo.MemberType, out value))
  703. {
  704. if (!isDryRun)
  705. {
  706. if (value is ValidationMarker)
  707. {
  708. Assert.That(IsValidating);
  709. }
  710. else
  711. {
  712. injectInfo.Setter(injectable, value);
  713. }
  714. }
  715. }
  716. else
  717. {
  718. value = Resolve(
  719. injectInfo.CreateInjectContext(
  720. this, args.Context, injectable, args.ConcreteIdentifier));
  721. if (injectInfo.Optional && value == null)
  722. {
  723. // Do not override in this case so it retains the hard-coded value
  724. }
  725. else
  726. {
  727. if (!isDryRun)
  728. {
  729. if (value is ValidationMarker)
  730. {
  731. Assert.That(IsValidating);
  732. }
  733. else
  734. {
  735. injectInfo.Setter(injectable, value);
  736. }
  737. }
  738. }
  739. }
  740. }
  741. foreach (var method in typeInfo.PostInjectMethods)
  742. {
  743. #if PROFILING_ENABLED
  744. using (ProfileBlock.Start("{0}.{1}()", injectableType, method.MethodInfo.Name))
  745. #endif
  746. {
  747. var paramValues = new List<object>();
  748. foreach (var injectInfo in method.InjectableInfo)
  749. {
  750. object value;
  751. if (!InjectUtil.PopValueWithType(args.ExtraArgs, injectInfo.MemberType, out value))
  752. {
  753. value = Resolve(
  754. injectInfo.CreateInjectContext(this, args.Context, injectable, args.ConcreteIdentifier));
  755. }
  756. if (value is ValidationMarker)
  757. {
  758. Assert.That(IsValidating);
  759. paramValues.Add(injectInfo.MemberType.GetDefaultValue());
  760. }
  761. else
  762. {
  763. paramValues.Add(value);
  764. }
  765. }
  766. if (!isDryRun)
  767. {
  768. method.MethodInfo.Invoke(injectable, paramValues.ToArray());
  769. }
  770. }
  771. }
  772. if (args.UseAllArgs && !args.ExtraArgs.IsEmpty())
  773. {
  774. throw Assert.CreateException(
  775. "Passed unnecessary parameters when injecting into type '{0}'. \nExtra Parameters: {1}\nObject graph:\n{2}",
  776. injectableType.Name(), String.Join(",", args.ExtraArgs.Select(x => x.Type.Name()).ToArray()), args.Context.GetObjectGraphString());
  777. }
  778. }
  779. #if !NOT_UNITY3D
  780. public GameObject InstantiatePrefabResourceExplicit(
  781. string resourcePath, List<TypeValuePair> extraArgs)
  782. {
  783. return InstantiatePrefabResourceExplicit(
  784. resourcePath, extraArgs, null);
  785. }
  786. public GameObject InstantiatePrefabResourceExplicit(
  787. string resourcePath, List<TypeValuePair> extraArgs, string groupName)
  788. {
  789. return InstantiatePrefabResourceExplicit(
  790. resourcePath, extraArgs, groupName, true);
  791. }
  792. public GameObject InstantiatePrefabResourceExplicit(
  793. string resourcePath, List<TypeValuePair> extraArgs,
  794. string groupName, bool useAllArgs)
  795. {
  796. var prefab = (GameObject)Resources.Load(resourcePath);
  797. Assert.IsNotNull(prefab, "Could not find prefab at resource location '{0}'".Fmt(resourcePath));
  798. return InstantiatePrefabExplicit(
  799. prefab, extraArgs, groupName, useAllArgs);
  800. }
  801. public GameObject InstantiatePrefabExplicit(
  802. UnityEngine.Object prefab, List<TypeValuePair> extraArgs)
  803. {
  804. return InstantiatePrefabExplicit(
  805. prefab, extraArgs, null);
  806. }
  807. public GameObject InstantiatePrefabExplicit(
  808. UnityEngine.Object prefab, List<TypeValuePair> extraArgs,
  809. string groupName)
  810. {
  811. return InstantiatePrefabExplicit(
  812. prefab, extraArgs, groupName, true);
  813. }
  814. public GameObject InstantiatePrefabExplicit(
  815. UnityEngine.Object prefab, List<TypeValuePair> extraArgs,
  816. string groupName, bool useAllArgs)
  817. {
  818. FlushBindings();
  819. var gameObj = CreateAndParentPrefab(prefab, groupName);
  820. InjectGameObjectExplicit(
  821. gameObj, true, extraArgs, useAllArgs);
  822. return gameObj;
  823. }
  824. // Don't use this unless you know what you're doing
  825. // You probably want to use InstantiatePrefab instead
  826. // This one will only create the prefab and will not inject into it
  827. public GameObject CreateAndParentPrefabResource(string resourcePath)
  828. {
  829. return CreateAndParentPrefabResource(resourcePath, null);
  830. }
  831. // Don't use this unless you know what you're doing
  832. // You probably want to use InstantiatePrefab instead
  833. // This one will only create the prefab and will not inject into it
  834. public GameObject CreateAndParentPrefabResource(string resourcePath, string groupName)
  835. {
  836. var prefab = (GameObject)Resources.Load(resourcePath);
  837. Assert.IsNotNull(prefab,
  838. "Could not find prefab at resource location '{0}'".Fmt(resourcePath));
  839. return CreateAndParentPrefab(prefab, groupName);
  840. }
  841. GameObject GetPrefabAsGameObject(UnityEngine.Object prefab)
  842. {
  843. if (prefab is GameObject)
  844. {
  845. return (GameObject)prefab;
  846. }
  847. Assert.That(prefab is Component, "Invalid type given for prefab. Given object name: '{0}'", prefab.name);
  848. return ((Component)prefab).gameObject;
  849. }
  850. // Don't use this unless you know what you're doing
  851. // You probably want to use InstantiatePrefab instead
  852. // This one will only create the prefab and will not inject into it
  853. public GameObject CreateAndParentPrefab(UnityEngine.Object prefab, string groupName)
  854. {
  855. Assert.That(!AssertOnNewGameObjects,
  856. "Given DiContainer does not support creating new game objects");
  857. FlushBindings();
  858. var prefabAsGameObject = GetPrefabAsGameObject(prefab);
  859. GameObject gameObj;
  860. if (IsValidating)
  861. {
  862. // We need to avoid triggering any Awake() method during validation
  863. // so temporarily disable the prefab so that the object gets
  864. // instantiated as disabled
  865. bool wasActive = prefabAsGameObject.activeSelf;
  866. prefabAsGameObject.SetActive(false);
  867. try
  868. {
  869. gameObj = (GameObject)GameObject.Instantiate(prefabAsGameObject);
  870. }
  871. finally
  872. {
  873. prefabAsGameObject.SetActive(wasActive);
  874. }
  875. }
  876. else
  877. {
  878. gameObj = (GameObject)GameObject.Instantiate(prefabAsGameObject);
  879. }
  880. gameObj.transform.SetParent(GetTransformGroup(groupName), false);
  881. return gameObj;
  882. }
  883. public GameObject CreateEmptyGameObject(string name)
  884. {
  885. return CreateEmptyGameObject(name, null);
  886. }
  887. public GameObject CreateEmptyGameObject(string name, string groupName)
  888. {
  889. Assert.That(!AssertOnNewGameObjects,
  890. "Given DiContainer does not support creating new game objects");
  891. FlushBindings();
  892. var gameObj = new GameObject(name);
  893. gameObj.transform.SetParent(GetTransformGroup(groupName), false);
  894. return gameObj;
  895. }
  896. public T InstantiatePrefabForComponentExplicit<T>(
  897. UnityEngine.Object prefab, List<TypeValuePair> extraArgs)
  898. {
  899. return (T)InstantiatePrefabForComponentExplicit(
  900. typeof(T), prefab, extraArgs);
  901. }
  902. // Note: Any arguments that are used will be removed from extraArgs
  903. public object InstantiatePrefabForComponentExplicit(
  904. Type componentType, UnityEngine.Object prefab, List<TypeValuePair> extraArgs)
  905. {
  906. return InstantiatePrefabForComponentExplicit(
  907. componentType, prefab, extraArgs, null);
  908. }
  909. public object InstantiatePrefabForComponentExplicit(
  910. Type componentType, UnityEngine.Object prefab, List<TypeValuePair> extraArgs,
  911. string groupName)
  912. {
  913. return InstantiatePrefabForComponentExplicit(
  914. componentType, prefab, groupName,
  915. new InjectArgs()
  916. {
  917. ExtraArgs = extraArgs,
  918. Context = new InjectContext(this, componentType, null),
  919. ConcreteIdentifier = null,
  920. UseAllArgs = true,
  921. });
  922. }
  923. // Note: Any arguments that are used will be removed from extraArgs
  924. public object InstantiatePrefabForComponentExplicit(
  925. Type componentType, UnityEngine.Object prefab, string groupName, InjectArgs args)
  926. {
  927. Assert.That(!AssertOnNewGameObjects,
  928. "Given DiContainer does not support creating new game objects");
  929. FlushBindings();
  930. Assert.That(prefab != null, "Null prefab found when instantiating game object");
  931. Assert.That(componentType.IsInterface() || componentType.DerivesFrom<Component>(),
  932. "Expected type '{0}' to derive from UnityEngine.Component", componentType.Name());
  933. var gameObj = (GameObject)GameObject.Instantiate(GetPrefabAsGameObject(prefab));
  934. gameObj.transform.SetParent(GetTransformGroup(groupName), false);
  935. gameObj.SetActive(true);
  936. return InjectGameObjectForComponentExplicit(
  937. gameObj, componentType, args);
  938. }
  939. Transform GetTransformGroup(string groupName)
  940. {
  941. Assert.That(!AssertOnNewGameObjects,
  942. "Given DiContainer does not support creating new game objects");
  943. if (DefaultParent == null)
  944. {
  945. if (groupName == null)
  946. {
  947. return null;
  948. }
  949. return (GameObject.Find("/" + groupName) ?? new GameObject(groupName)).transform;
  950. }
  951. if (groupName == null)
  952. {
  953. return DefaultParent;
  954. }
  955. foreach (Transform child in DefaultParent)
  956. {
  957. if (child.name == groupName)
  958. {
  959. return child;
  960. }
  961. }
  962. var group = new GameObject(groupName).transform;
  963. group.SetParent(DefaultParent, false);
  964. return group;
  965. }
  966. #endif
  967. public T Instantiate<T>()
  968. {
  969. return Instantiate<T>(new object[0]);
  970. }
  971. // See comment in IInstantiator.cs for description of this method
  972. public T Instantiate<T>(IEnumerable<object> extraArgs)
  973. {
  974. var result = Instantiate(typeof(T), extraArgs);
  975. if (IsValidating && !(result is T))
  976. {
  977. Assert.That(result is ValidationMarker);
  978. return default(T);
  979. }
  980. return (T)result;
  981. }
  982. public object Instantiate(Type concreteType)
  983. {
  984. return Instantiate(concreteType, new object[0]);
  985. }
  986. // See comment in IInstantiator.cs for description of this method
  987. public object Instantiate(
  988. Type concreteType, IEnumerable<object> extraArgs)
  989. {
  990. Assert.That(!extraArgs.ContainsItem(null),
  991. "Null value given to factory constructor arguments when instantiating object with type '{0}'. In order to use null use InstantiateExplicit", concreteType);
  992. return InstantiateExplicit(
  993. concreteType, InjectUtil.CreateArgList(extraArgs));
  994. }
  995. #if !NOT_UNITY3D
  996. // See comment in IInstantiator.cs for description of this method
  997. public TContract InstantiateComponent<TContract>(GameObject gameObject)
  998. where TContract : Component
  999. {
  1000. return InstantiateComponent<TContract>(gameObject, new object[0]);
  1001. }
  1002. // See comment in IInstantiator.cs for description of this method
  1003. public TContract InstantiateComponent<TContract>(
  1004. GameObject gameObject, IEnumerable<object> extraArgs)
  1005. where TContract : Component
  1006. {
  1007. return (TContract)InstantiateComponent(typeof(TContract), gameObject, extraArgs);
  1008. }
  1009. public Component InstantiateComponent(
  1010. Type componentType, GameObject gameObject)
  1011. {
  1012. return InstantiateComponent(componentType, gameObject, new object[0]);
  1013. }
  1014. // See comment in IInstantiator.cs for description of this method
  1015. public Component InstantiateComponent(
  1016. Type componentType, GameObject gameObject, IEnumerable<object> extraArgs)
  1017. {
  1018. return InstantiateComponentExplicit(
  1019. componentType, gameObject, InjectUtil.CreateArgList(extraArgs));
  1020. }
  1021. public Component InstantiateComponentExplicit(
  1022. Type componentType, GameObject gameObject, List<TypeValuePair> extraArgs)
  1023. {
  1024. Assert.That(componentType.DerivesFrom<Component>());
  1025. FlushBindings();
  1026. var monoBehaviour = (Component)gameObject.AddComponent(componentType);
  1027. InjectExplicit(monoBehaviour, extraArgs);
  1028. return monoBehaviour;
  1029. }
  1030. public GameObject InstantiatePrefab(UnityEngine.Object prefab)
  1031. {
  1032. return InstantiatePrefab(prefab, new object[0]);
  1033. }
  1034. public GameObject InstantiatePrefab(
  1035. UnityEngine.Object prefab, IEnumerable<object> extraArgs)
  1036. {
  1037. return InstantiatePrefab(
  1038. prefab, extraArgs, null);
  1039. }
  1040. public GameObject InstantiatePrefab(
  1041. UnityEngine.Object prefab, IEnumerable<object> extraArgs, string groupName)
  1042. {
  1043. return InstantiatePrefabExplicit(
  1044. prefab, InjectUtil.CreateArgList(extraArgs),
  1045. groupName);
  1046. }
  1047. // See comment in IInstantiator.cs for description of this method
  1048. public GameObject InstantiatePrefabResource(string resourcePath)
  1049. {
  1050. return InstantiatePrefabResource(resourcePath, new object[0]);
  1051. }
  1052. // See comment in IInstantiator.cs for description of this method
  1053. public GameObject InstantiatePrefabResource(
  1054. string resourcePath, IEnumerable<object> extraArgs)
  1055. {
  1056. return InstantiatePrefabResource(
  1057. resourcePath, extraArgs, null);
  1058. }
  1059. // See comment in IInstantiator.cs for description of this method
  1060. public GameObject InstantiatePrefabResource(
  1061. string resourcePath, IEnumerable<object> extraArgs, string groupName)
  1062. {
  1063. return InstantiatePrefabResourceExplicit(
  1064. resourcePath, InjectUtil.CreateArgList(extraArgs),
  1065. groupName);
  1066. }
  1067. /////////////// InstantiatePrefabForComponent
  1068. public T InstantiatePrefabForComponent<T>(UnityEngine.Object prefab)
  1069. {
  1070. return InstantiatePrefabForComponent<T>(prefab, new object[0]);
  1071. }
  1072. public T InstantiatePrefabForComponent<T>(
  1073. UnityEngine.Object prefab, IEnumerable<object> extraArgs)
  1074. {
  1075. return (T)InstantiatePrefabForComponent(
  1076. typeof(T), prefab, extraArgs);
  1077. }
  1078. public object InstantiatePrefabForComponent(
  1079. Type concreteType, UnityEngine.Object prefab, IEnumerable<object> extraArgs)
  1080. {
  1081. return InstantiatePrefabForComponentExplicit(
  1082. concreteType, prefab,
  1083. InjectUtil.CreateArgList(extraArgs));
  1084. }
  1085. /////////////// InstantiatePrefabForComponent
  1086. // See comment in IInstantiator.cs for description of this method
  1087. public T InstantiatePrefabResourceForComponent<T>(string resourcePath)
  1088. {
  1089. return InstantiatePrefabResourceForComponent<T>(resourcePath, new object[0]);
  1090. }
  1091. // See comment in IInstantiator.cs for description of this method
  1092. public T InstantiatePrefabResourceForComponent<T>(
  1093. string resourcePath, IEnumerable<object> extraArgs)
  1094. {
  1095. return (T)InstantiatePrefabResourceForComponent(typeof(T), resourcePath, extraArgs);
  1096. }
  1097. // See comment in IInstantiator.cs for description of this method
  1098. public object InstantiatePrefabResourceForComponent(
  1099. Type concreteType, string resourcePath, IEnumerable<object> extraArgs)
  1100. {
  1101. Assert.That(!extraArgs.ContainsItem(null),
  1102. "Null value given to factory constructor arguments when instantiating object with type '{0}'. In order to use null use InstantiatePrefabForComponentExplicit", concreteType);
  1103. return InstantiatePrefabResourceForComponentExplicit(
  1104. concreteType, resourcePath, InjectUtil.CreateArgList(extraArgs));
  1105. }
  1106. public T InstantiatePrefabResourceForComponentExplicit<T>(
  1107. string resourcePath, List<TypeValuePair> extraArgs)
  1108. {
  1109. return (T)InstantiatePrefabResourceForComponentExplicit(
  1110. typeof(T), resourcePath, extraArgs);
  1111. }
  1112. // Note: Any arguments that are used will be removed from extraArgs
  1113. public object InstantiatePrefabResourceForComponentExplicit(
  1114. Type componentType, string resourcePath, List<TypeValuePair> extraArgs)
  1115. {
  1116. return InstantiatePrefabResourceForComponentExplicit(
  1117. componentType, resourcePath, null,
  1118. new InjectArgs()
  1119. {
  1120. ExtraArgs = extraArgs,
  1121. Context = new InjectContext(this, componentType, null),
  1122. ConcreteIdentifier = null,
  1123. UseAllArgs = true,
  1124. });
  1125. }
  1126. // Note: Any arguments that are used will be removed from extraArgs
  1127. public object InstantiatePrefabResourceForComponentExplicit(
  1128. Type componentType, string resourcePath, string groupName, InjectArgs args)
  1129. {
  1130. var prefab = (GameObject)Resources.Load(resourcePath);
  1131. Assert.IsNotNull(prefab,
  1132. "Could not find prefab at resource location '{0}'".Fmt(resourcePath));
  1133. return InstantiatePrefabForComponentExpli