Beispiel #1
0
        public static IEnumerable <ZenjectResolveException> ValidateObjectGraph(
            DiContainer container, Type concreteType, params Type[] extras)
        {
            using (container.PushLookup(concreteType))
            {
                var typeInfo   = TypeAnalyzer.GetInfo(concreteType);
                var extrasList = extras.ToList();

                foreach (var dependInfo in typeInfo.AllInjectables)
                {
                    Assert.IsEqual(dependInfo.ParentType, concreteType);

                    if (TryTakingFromExtras(dependInfo.MemberType, extrasList))
                    {
                        continue;
                    }

                    var context = dependInfo.CreateInjectContext(container, null);

                    foreach (var error in ValidateContract(container, context))
                    {
                        yield return(error);
                    }
                }

                if (!extrasList.IsEmpty())
                {
                    yield return(new ZenjectResolveException(
                                     "Found unnecessary extra parameters passed when injecting into '{0}' with types '{1}'.  \nObject graph:\n{2}"
                                     .Fmt(concreteType.Name(), String.Join(",", extrasList.Select(x => x.Name()).ToArray()), DiContainer.GetCurrentObjectGraph())));
                }
            }
        }
Beispiel #2
0
 public IEnumerable <Type> GetDependencyContracts(Type contract)
 {
     foreach (var injectMember in TypeAnalyzer.GetInfo(contract).AllInjectables)
     {
         yield return(injectMember.ContractType);
     }
 }
        public List <object> GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction)
        {
            Assert.IsNotNull(context);

            Assert.That(context.ObjectType.DerivesFrom <Component>(),
                        "Object '{0}' can only be injected into MonoBehaviour's since it was bound with 'FromNewComponentSibling'. Attempted to inject into non-MonoBehaviour '{1}'",
                        context.MemberType, context.ObjectType);

            object instance;

            if (!_container.IsValidating || TypeAnalyzer.ShouldAllowDuringValidation(_componentType))
            {
                var gameObj = ((Component)context.ObjectInstance).gameObject;

                instance = gameObj.GetComponent(_componentType);

                if (instance != null)
                {
                    injectAction = null;
                    return(new List <object>()
                    {
                        instance
                    });
                }

                instance = gameObj.AddComponent(_componentType);
            }
            else
            {
                instance = new ValidationMarker(_componentType);
            }

            // Note that we don't just use InstantiateComponentOnNewGameObjectExplicit here
            // because then circular references don't work

            var injectArgs = new InjectArgs()
            {
                ExtraArgs          = _extraArguments.Concat(args).ToList(),
                Context            = context,
                ConcreteIdentifier = _concreteIdentifier
            };

            injectAction = () =>
            {
                _container.InjectExplicit(instance, _componentType, injectArgs);

                Assert.That(injectArgs.ExtraArgs.IsEmpty());

                if (_instantiateCallback != null)
                {
                    _instantiateCallback(context, instance);
                }
            };

            return(new List <object>()
            {
                instance
            });
        }
Beispiel #4
0
        public List <object> GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction)
        {
            Assert.IsEmpty(args);
            Assert.IsNotNull(context);

            Assert.That(typeof(TReturn).DerivesFromOrEqual(context.MemberType));

            injectAction = null;
            if (_container.IsValidating && !TypeAnalyzer.ShouldAllowDuringValidation(context.MemberType))
            {
                return(new List <object>()
                {
                    new ValidationMarker(typeof(TReturn))
                });
            }
            else
            {
                var result = _method(context);

                if (result == null)
                {
                    throw Assert.CreateException(
                              "Method '{0}' returned null when list was expected. Object graph:\n {1}",
                              _method.ToDebugString(), context.GetObjectGraphString());
                }

                return(result.Cast <object>().ToList());
            }
        }
        public IEnumerator <List <object> > GetAllInstancesWithInjectSplit(InjectContext context, List <TypeValuePair> args)
        {
            Assert.IsNotNull(context);

            bool autoInject = false;

            var injectArgs = new InjectArgs()
            {
                TypeInfo           = TypeAnalyzer.GetInfo(GetTypeToCreate(context.MemberType)),
                ExtraArgs          = _extraArguments.Concat(args).ToList(),
                Context            = context,
                ConcreteIdentifier = _concreteIdentifier,
                UseAllArgs         = false,
            };

            var instance = _container.InstantiateExplicit(
                autoInject, injectArgs);

            // Return before property/field/method injection to allow circular dependencies
            yield return(new List <object>()
            {
                instance
            });

            injectArgs.UseAllArgs = true;

            _container.InjectExplicit(instance, injectArgs);
        }
Beispiel #6
0
        public void GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction, List <object> buffer)
        {
            Assert.IsEmpty(args);
            Assert.IsNotNull(context);

            injectAction = null;
            if (_container.IsValidating && !TypeAnalyzer.ShouldAllowDuringValidation(context.MemberType))
            {
                buffer.Add(new ValidationMarker(context.MemberType));
            }
            else
            {
                var result = _method(context);

                if (result == null)
                {
                    Assert.That(!context.MemberType.IsPrimitive(),
                                "Invalid value returned from FromMethod.  Expected non-null.");
                }
                else
                {
                    Assert.That(result.GetType().DerivesFromOrEqual(context.MemberType));
                }

                buffer.Add(result);
            }
        }
        public List <object> GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction)
        {
            Assert.IsEmpty(args);
            Assert.IsNotNull(context);

            Assert.That(typeof(TReturn).DerivesFromOrEqual(context.MemberType));

            injectAction = null;
            if (_container.IsValidating && !TypeAnalyzer.ShouldAllowDuringValidation(context.MemberType))
            {
                return(new List <object>()
                {
                    new ValidationMarker(typeof(TReturn))
                });
            }
            else
            {
                // We cannot do a null assert here because in some cases they might intentionally
                // return null
                return(new List <object>()
                {
                    _method(context)
                });
            }
        }
Beispiel #8
0
        public void GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction, List <object> buffer)
        {
            Assert.IsEmpty(args);
            Assert.IsNotNull(context);

            injectAction = null;
            if (_container.IsValidating && !TypeAnalyzer.ShouldAllowDuringValidation(context.MemberType))
            {
                buffer.Add(new ValidationMarker(context.MemberType));
            }
            else
            {
                var result = _method(context);

                if (result == null)
                {
                    throw Assert.CreateException(
                              "Method '{0}' returned null when list was expected. Object graph:\n {1}",
                              _method.ToDebugString(), context.GetObjectGraphString());
                }

                foreach (var obj in result)
                {
                    buffer.Add(obj);
                }
            }
        }
Beispiel #9
0
        public void GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction, List <object> buffer)
        {
            Assert.IsNotNull(context);

            Assert.That(context.ObjectType.DerivesFrom <Component>(),
                        "Object '{0}' can only be injected into MonoBehaviour's since it was bound with 'FromNewComponentSibling'. Attempted to inject into non-MonoBehaviour '{1}'",
                        context.MemberType, context.ObjectType);

            object instance;

            if (!_container.IsValidating || TypeAnalyzer.ShouldAllowDuringValidation(_componentType))
            {
                var gameObj = ((Component)context.ObjectInstance).gameObject;

                var componentInstance = gameObj.GetComponent(_componentType);
                instance = componentInstance;

                // Use componentInstance so that it triggers unity's overloaded comparison operator
                // So if the component is there but missing then it returns null
                // (https://github.com/svermeulen/Zenject/issues/582)
                if (componentInstance != null)
                {
                    injectAction = null;
                    buffer.Add(instance);
                    return;
                }

                instance = gameObj.AddComponent(_componentType);
            }
            else
            {
                instance = new ValidationMarker(_componentType);
            }

            // Note that we don't just use InstantiateComponentOnNewGameObjectExplicit here
            // because then circular references don't work

            injectAction = () =>
            {
                var extraArgs = ZenPools.SpawnList <TypeValuePair>();

                extraArgs.AllocFreeAddRange(_extraArguments);
                extraArgs.AllocFreeAddRange(args);

                _container.InjectExplicit(instance, _componentType, extraArgs, context, _concreteIdentifier);

                Assert.That(extraArgs.IsEmpty());
                ZenPools.DespawnList(extraArgs);

                if (_instantiateCallback != null)
                {
                    _instantiateCallback(context, instance);
                }
            };

            buffer.Add(instance);
        }
Beispiel #10
0
        object InstantiateInternal(
            Type concreteType, IEnumerable <TypeValuePair> extraArgMapParam, InjectContext currentContext)
        {
#if !ZEN_NOT_UNITY3D
            Assert.That(!concreteType.DerivesFrom <UnityEngine.Component>(),
                        "Error occurred while instantiating object of type '{0}'. Instantiator should not be used to create new mono behaviours.  Must use GameObjectInstantiator, GameObjectFactory, or GameObject.Instantiate.", concreteType.Name());
#endif

            var typeInfo = TypeAnalyzer.GetInfo(concreteType);

            if (typeInfo.InjectConstructor == null)
            {
                throw new ZenjectResolveException(
                          "More than one (or zero) constructors found for type '{0}' when creating dependencies.  Use one [Inject] attribute to specify which to use.".Fmt(concreteType));
            }

            // Make a copy since we remove from it below
            var extraArgMap = extraArgMapParam.ToList();
            var paramValues = new List <object>();

            foreach (var injectInfo in typeInfo.ConstructorInjectables)
            {
                object value;

                if (!InstantiateUtil.PopValueWithType(extraArgMap, injectInfo.MemberType, out value))
                {
                    value = Resolve(injectInfo.CreateInjectContext(this, currentContext, null));
                }

                paramValues.Add(value);
            }

            object newObj;

            try
            {
                using (ProfileBlock.Start("{0}.{0}()", concreteType))
                {
                    newObj = typeInfo.InjectConstructor.Invoke(paramValues.ToArray());
                }
            }
            catch (Exception e)
            {
                throw new ZenjectResolveException(
                          "Error occurred while instantiating object with type '{0}'".Fmt(concreteType.Name()), e);
            }

            Inject(newObj, extraArgMap, true, typeInfo, currentContext);

            return(newObj);
        }
        IEnumerable <InjectableInfo> GetAllInjectableIncludingBaseTypes()
        {
            var info = TypeAnalyzer.GetInfo(_installerType);

            while (info != null)
            {
                foreach (var injectable in info.AllInjectables)
                {
                    yield return(injectable);
                }

                info = info.BaseTypeInfo;
            }
        }
        void InitInstance(InjectContext context)
        {
            var concreteType = GetTypeToInstantiate(context.MemberType);

            bool autoInject = false;

            _instance = _container.InstantiateExplicit(
                concreteType, new List <TypeValuePair>(), context, Id.Identifier, autoInject);

            Assert.IsNotNull(_instance);

            // Inject after we've instantiated and set _instance so that we can support circular dependencies
            // as PostInject or field parameters
            _container.InjectExplicit(
                _instance, Enumerable.Empty <TypeValuePair>(), true,
                TypeAnalyzer.GetInfo(_instance.GetType()), context, Id.Identifier);
        }
        public object GetInstance(InjectContext context)
        {
            if (!_hasInstance)
            {
                if (_createMethod != null)
                {
                    _instance = _createMethod(context);

                    if (_instance == null)
                    {
                        throw new ZenjectResolveException(
                                  "Unable to instantiate type '{0}' in SingletonLazyCreator".Fmt(context.MemberType));
                    }

                    _hasInstance = true;
                }
                else
                {
                    var concreteType = GetTypeToInstantiate(context.MemberType);

                    bool autoInject = false;

                    _instance = _container.InstantiateExplicit(
                        concreteType, new List <TypeValuePair>(), context, _id.Identifier, autoInject);

                    Assert.IsNotNull(_instance);

                    _hasInstance = true;

                    // Inject after we've instantiated and set the _hasInstance flag so that we can support circular dependencies
                    // as PostInject or field parameters
                    _container.InjectExplicit(
                        _instance, Enumerable.Empty <TypeValuePair>(), true,
                        TypeAnalyzer.GetInfo(_instance.GetType()), context, _id.Identifier);
                }
            }

            return(_instance);
        }
Beispiel #14
0
        public IEnumerator <List <object> > GetAllInstancesWithInjectSplit(InjectContext context, List <TypeValuePair> args)
        {
            Assert.IsNotNull(context);

            object instance;

            // We still want to make sure we can get the game object during validation
            var gameObj = GetGameObject(context);

            if (!_container.IsValidating || DiContainer.CanCreateOrInjectDuringValidation(_componentType))
            {
                instance = gameObj.AddComponent(_componentType);
            }
            else
            {
                instance = new ValidationMarker(_componentType);
            }

            // Note that we don't just use InstantiateComponentOnNewGameObjectExplicit here
            // because then circular references don't work
            yield return(new List <object>()
            {
                instance
            });

            var injectArgs = new InjectArgs()
            {
                ExtraArgs          = _extraArguments.Concat(args).ToList(),
                UseAllArgs         = true,
                TypeInfo           = TypeAnalyzer.GetInfo(_componentType),
                Context            = context,
                ConcreteIdentifier = _concreteIdentifier,
            };

            _container.InjectExplicit(instance, injectArgs);

            Assert.That(injectArgs.ExtraArgs.IsEmpty());
        }
Beispiel #15
0
        public List <object> GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction)
        {
            Assert.IsEmpty(args);
            Assert.IsNotNull(context);

            injectAction = null;
            if (_container.IsValidating && !TypeAnalyzer.ShouldAllowDuringValidation(context.MemberType))
            {
                return(new List <object>()
                {
                    new ValidationMarker(context.MemberType)
                });
            }
            else
            {
                var result = _method(context);

                if (result == null)
                {
#if !UNITY_WSA
                    Assert.That(context.MemberType.IsPrimitive,
                                "Invalid value returned from FromMethod.  Expected non-null.");
#endif
                }
                else
                {
                    Assert.That(result.GetType().DerivesFromOrEqual(context.MemberType));
                }

                return(new List <object>()
                {
                    result
                });
            }
        }
        DiContainer CreateTempContainer(List <TypeValuePair> args)
        {
            var tempSubContainer = Container.CreateSubContainer();

            var installerInjectables = TypeAnalyzer.GetInfo(_installerType);

            foreach (var argPair in args)
            {
                // We need to intelligently match on the exact parameters here to avoid the issue
                // brought up in github issue #217
                var match = installerInjectables.AllInjectables
                            .Where(x => argPair.Type.DerivesFromOrEqual(x.MemberType))
                            .OrderBy(x => ZenUtilInternal.GetInheritanceDelta(argPair.Type, x.MemberType)).FirstOrDefault();

                Assert.That(match != null,
                            "Could not find match for argument type '{0}' when injecting into sub container installer '{1}'",
                            argPair.Type, _installerType);

                tempSubContainer.Bind(match.MemberType)
                .FromInstance(argPair.Value).WhenInjectedInto(_installerType);
            }

            return(tempSubContainer);
        }
 public static void Inject(DiContainer container, object injectable, IEnumerable <object> additional, bool shouldUseAll)
 {
     Inject(container, injectable, additional, shouldUseAll, TypeAnalyzer.GetInfo(injectable.GetType()));
 }
Beispiel #18
0
        public void GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction, List <object> buffer)
        {
            Assert.IsNotNull(context);

            object instance;

            // We still want to make sure we can get the game object during validation
            var gameObj = GetGameObject(context);

            var wasActive = gameObj.activeSelf;

            if (wasActive && ShouldToggleActive)
            {
                // We need to do this in some cases to ensure that [Inject] always gets
                // called before awake / start
                gameObj.SetActive(false);
            }

            if (!_container.IsValidating || TypeAnalyzer.ShouldAllowDuringValidation(_componentType))
            {
                if (_componentType == typeof(Transform))
                // Treat transform as a special case because it's the one component that's always automatically added
                // Otherwise, calling AddComponent below will fail and return null
                // This is nice to allow doing things like
                //      Container.Bind<Transform>().FromNewComponentOnNewGameObject();
                {
                    instance = gameObj.transform;
                }
                else
                {
                    instance = gameObj.AddComponent(_componentType);
                }

                Assert.IsNotNull(instance);
            }
            else
            {
                instance = new ValidationMarker(_componentType);
            }

            injectAction = () =>
            {
                try
                {
                    var extraArgs = ZenPools.SpawnList <TypeValuePair>();

                    extraArgs.AllocFreeAddRange(_extraArguments);
                    extraArgs.AllocFreeAddRange(args);

                    _container.InjectExplicit(instance, _componentType, extraArgs, context, _concreteIdentifier);

                    Assert.That(extraArgs.Count == 0);

                    ZenPools.DespawnList(extraArgs);

                    if (_instantiateCallback != null)
                    {
                        _instantiateCallback(context, instance);
                    }
                }
                finally
                {
                    if (wasActive && ShouldToggleActive)
                    {
                        gameObj.SetActive(true);
                    }
                }
            };

            buffer.Add(instance);
        }
Beispiel #19
0
 public void InjectExplicit(object injectable, List <TypeValuePair> additional, InjectContext context)
 {
     InjectExplicit(
         injectable, additional, true,
         TypeAnalyzer.GetInfo(injectable.GetType()), context, null);
 }
        public List <object> GetAllInstancesWithInjectSplit(
            InjectContext context, List <TypeValuePair> args, out Action injectAction)
        {
            Assert.IsNotNull(context);

            object instance;

            // We still want to make sure we can get the game object during validation
            var gameObj = GetGameObject(context);

            var wasActive = gameObj.activeSelf;

            if (wasActive && ShouldToggleActive)
            {
                // We need to do this in some cases to ensure that [Inject] always gets
                // called before awake / start
                gameObj.SetActive(false);
            }

            if (!_container.IsValidating || TypeAnalyzer.ShouldAllowDuringValidation(_componentType))
            {
                if (_componentType == typeof(Transform))
                // Treat transform as a special case because it's the one component that's always automatically added
                // Otherwise, calling AddComponent below will fail and return null
                // This is nice to allow doing things like
                //      Container.Bind<Transform>().FromNewComponentOnNewGameObject();
                {
                    instance = gameObj.transform;
                }
                else
                {
                    instance = gameObj.AddComponent(_componentType);
                }

                Assert.IsNotNull(instance);
            }
            else
            {
                instance = new ValidationMarker(_componentType);
            }

            injectAction = () =>
            {
                try
                {
                    var injectArgs = new InjectArgs()
                    {
                        ExtraArgs          = _extraArguments.Concat(args).ToList(),
                        Context            = context,
                        ConcreteIdentifier = _concreteIdentifier
                    };

                    _container.InjectExplicit(instance, _componentType, injectArgs);
                }
                finally
                {
                    if (wasActive && ShouldToggleActive)
                    {
                        gameObj.SetActive(true);
                    }
                }
            };
            return(new List <object>()
            {
                instance
            });
        }
Beispiel #21
0
        object InstantiateInternal(
            Type concreteType, IEnumerable <TypeValuePair> extraArgs, InjectContext currentContext, string concreteIdentifier, bool autoInject)
        {
#if !ZEN_NOT_UNITY3D
            Assert.That(!concreteType.DerivesFrom <UnityEngine.Component>(),
                        "Error occurred while instantiating object of type '{0}'. Instantiator should not be used to create new mono behaviours.  Must use InstantiatePrefabForComponent, InstantiatePrefab, InstantiateComponentOnNewGameObject, InstantiateGameObject, or InstantiateComponent.  You may also want to use GameObjectFactory class or plain old GameObject.Instantiate.", concreteType.Name());
#endif

            var typeInfo = TypeAnalyzer.GetInfo(concreteType);

            if (typeInfo.InjectConstructor == null)
            {
                throw new ZenjectResolveException(
                          "More than one (or zero) constructors found for type '{0}' when creating dependencies.  Use one [Inject] attribute to specify which to use.".Fmt(concreteType));
            }

            // Make a copy since we remove from it below
            var extraArgList = extraArgs.ToList();
            var paramValues  = new List <object>();

            foreach (var injectInfo in typeInfo.ConstructorInjectables)
            {
                object value;

                if (!InstantiateUtil.PopValueWithType(extraArgList, injectInfo.MemberType, out value))
                {
                    value = Resolve(injectInfo.CreateInjectContext(this, currentContext, null, concreteIdentifier));
                }

                paramValues.Add(value);
            }

            object newObj;

            try
            {
#if PROFILING_ENABLED
                using (ProfileBlock.Start("{0}.{0}()", concreteType))
#endif
                {
                    newObj = typeInfo.InjectConstructor.Invoke(paramValues.ToArray());
                }
            }
            catch (Exception e)
            {
                throw new ZenjectResolveException(
                          "Error occurred while instantiating object with type '{0}'".Fmt(concreteType.Name()), e);
            }

            if (autoInject)
            {
                InjectExplicit(newObj, extraArgList, true, typeInfo, currentContext, concreteIdentifier);
            }
            else
            {
                if (!extraArgList.IsEmpty())
                {
                    throw new ZenjectResolveException(
                              "Passed unnecessary parameters when injecting into type '{0}'. \nExtra Parameters: {1}\nObject graph:\n{2}"
                              .Fmt(newObj.GetType().Name(), String.Join(",", extraArgList.Select(x => x.Type.Name()).ToArray()), currentContext.GetObjectGraphString()));
                }
            }

            return(newObj);
        }
Beispiel #22
0
 public static void Inject(this DiContainer container, object injectable, InjectContext context)
 {
     container.Inject(
         injectable, Enumerable.Empty <object>(), false,
         TypeAnalyzer.GetInfo(injectable.GetType()), context);
 }
Beispiel #23
0
 public static void Inject(this DiContainer container, object injectable, IEnumerable <object> additional, InjectContext context)
 {
     container.Inject(injectable, additional, false,
                      TypeAnalyzer.GetInfo(injectable.GetType()), context);
 }
Beispiel #24
0
 public static void Inject(this DiContainer container, object injectable, IEnumerable <object> additional, bool shouldUseAll)
 {
     container.Inject(
         injectable, additional, shouldUseAll,
         TypeAnalyzer.GetInfo(injectable.GetType()), new InjectContext(container, injectable.GetType(), null));
 }
Beispiel #25
0
 public void Inject(
     object injectable, IEnumerable <object> additional, bool shouldUseAll, InjectContext context)
 {
     Inject(
         injectable, additional, shouldUseAll, context, TypeAnalyzer.GetInfo(injectable.GetType()));
 }