コード例 #1
0
        void Awake()
        {
            Stopwatch stopwatch = CreateAndStartStopwatch();

            sceneInjector = UniInjectUtils.CreateInjector();
            UniInjectUtils.SceneInjector = sceneInjector;

            // Bind the scene injector itself.
            // This way it can be injected at the scene start
            // and be used to inject newly created scripts at runtime.
            sceneInjector.AddBindingForInstance(sceneInjector);

            // (1) Iterate over scene hierarchy, thereby
            // (a) find IBinder instances.
            // (b) find scripts that need injection and how their members should be injected.
            AnalyzeScene();

            // (2) Store bindings in the sceneInjector
            CreateBindings();

            // (3) Inject the bindings from the sceneInjector into the objects that need injection.
            InjectScriptsThatNeedInjection();

            StopAndLogTime(stopwatch, $"SceneInjectionManager - Analyzing, binding and injecting scene took {stopwatch.ElapsedMilliseconds} ms");

            // (4) Notify listeners that scene injection has finished
            foreach (ISceneInjectionFinishedListener listener in sceneInjectionFinishedListeners)
            {
                listener.OnSceneInjectionFinished();
            }
        }
コード例 #2
0
        private void Inject(object target, object injectionKey)
        {
            // For circular dependencies, the object that is currently created for the injectionKey is stored temporarily.
            // The map is prioritized when resolving dependencies.
            // Thus, further newly created objects (i.e. dependencies of the result that is constructed here)
            // that have a dependency to injectionKey (i.e. to the result that is constructed here),
            // can have the object injected that has already been instantiated here.
            injectionKeyToObjectWithOngoingInjectionMap.Add(injectionKey, target);

            // Find all members to be injected via reflection.
            List <InjectionData> injectionDatas = UniInjectUtils.GetInjectionDatas(target.GetType());

            // Inject existing bindings into the fields.
            foreach (InjectionData injectionData in injectionDatas)
            {
                Inject(target, injectionData);
            }

            injectionKeyToObjectWithOngoingInjectionMap.Remove(injectionKey);

            // Notify target that its injection is now finished.
            if (target is IInjectionFinishedListener)
            {
                (target as IInjectionFinishedListener).OnInjectionFinished();
            }
        }
コード例 #3
0
        private void InjectMemberFromUnitySearchMethod(MonoBehaviour script, MemberInfo memberInfo, SearchMethods searchMethod, bool isOptional)
        {
            Type componentType = ReflectionUtils.GetTypeOfFieldOrProperty(script, memberInfo);

            // For testing, searching in the scene hierarchy using a Unity method can be simulated to return a mockup for a component.
            object component = GetComponentFromUnitySearchMethodMockups(script, searchMethod, componentType);

            if (component == null)
            {
                // No mockup found, thus use the real Unity search method.
                component = UniInjectUtils.InvokeUnitySearchMethod(script, searchMethod, componentType);
            }

            if (component != null)
            {
                if (memberInfo is FieldInfo)
                {
                    (memberInfo as FieldInfo).SetValue(script, component);
                }
                else if (memberInfo is PropertyInfo)
                {
                    (memberInfo as PropertyInfo).SetValue(script, component);
                }
                else
                {
                    throw new Exception($"Cannot inject member {script.name}.{memberInfo}."
                                        + $" Only Fields and Properties are supported for component injection via Unity methods.");
                }
            }
            else if (!isOptional)
            {
                throw new Exception($"Cannot inject member {script.name}.{memberInfo.Name}."
                                    + $" No component of type {componentType} found using method {searchMethod}");
            }
        }
コード例 #4
0
        private static int CheckInjectableFromUnitySearchMethod(MonoBehaviour script, Type type, InjectionData injectionData)
        {
            if (injectionData.InjectionKeys.Length > 1)
            {
                // If there are multiple keys, then it must be for a method or constructor with multiple parameters
                LogErrorCannotBeInjected($"The search method {injectionData.searchMethod} can only be used on a field or property.",
                                         script, type, injectionData.MemberInfo);
                return(1);
            }

            object injectionKey = injectionData.InjectionKeys[0];

            if (!(injectionKey is Type))
            {
                LogErrorCannotBeInjected($"The search method {injectionData.searchMethod} can not be used with a custom key.",
                                         script, type, injectionData.MemberInfo);
                return(1);
            }
            Type componentType = injectionKey as Type;

            UnityEngine.Object searchResult = UniInjectUtils.InvokeUnitySearchMethod(script, injectionData.searchMethod, componentType);
            if (searchResult == null)
            {
                LogErrorCannotBeInjected($"No instance of {componentType} found using {injectionData.searchMethod}.",
                                         script, type, injectionData.MemberInfo);
                return(1);
            }

            return(0);
        }
コード例 #5
0
        private static int CheckInjectable(MonoBehaviour script, Type type, List <IBinding> bindings)
        {
            int errorCount = 0;

            List <InjectionData> injectionDatas = UniInjectUtils.GetInjectionDatas(type);

            foreach (InjectionData injectionData in injectionDatas)
            {
                if (injectionData.isOptional)
                {
                    continue;
                }

                if (injectionData.searchMethod == SearchMethods.SearchInBindings)
                {
                    errorCount += CheckInjectableFromBindings(script, type, bindings, injectionData);
                }
                else
                {
                    errorCount += CheckInjectableFromUnitySearchMethod(script, type, injectionData);
                }
            }

            return(errorCount);
        }
コード例 #6
0
        internal object[] GetValuesForConstructorInjection(Type type)
        {
            if (getValuesForConstructorInjectionVisitedTypes.Contains(type))
            {
                throw new CyclicConstructorDependenciesException($"Circular dependencies in the constructor parameters of type {type}");
            }
            getValuesForConstructorInjectionVisitedTypes.Add(type);

            ConstructorInjectionData constructorInjectionData = UniInjectUtils.GetConstructorInjectionData(type);

            object[] injectionKeys = constructorInjectionData.InjectionKeys;
            object[] result        = GetValuesForInjectionKeys(injectionKeys);

            getValuesForConstructorInjectionVisitedTypes.Remove(type);
            return(result);
        }
コード例 #7
0
        private void AnalyzeScriptsRecursively(GameObject gameObject)
        {
            MonoBehaviour[] scripts = gameObject.GetComponents <MonoBehaviour>();
            foreach (MonoBehaviour script in scripts)
            {
                // The script can be null if it is a missing component.
                if (script == null)
                {
                    continue;
                }

                // Analyzing a type for InjectionData is costly.
                // The types of the UnityEngine do not make use of UniInject.
                // Thus, the scripts from the UnityEngine itself should be skipped for better performance.
                Type type = script.GetType();
                if (!string.IsNullOrEmpty(type.Namespace) && type.Namespace.StartsWith("UnityEngine."))
                {
                    continue;
                }

                if (script is IBinder)
                {
                    binders.Add(script as IBinder);
                }

                if (script is ISceneInjectionFinishedListener)
                {
                    sceneInjectionFinishedListeners.Add(script as ISceneInjectionFinishedListener);
                }

                if ((!onlyInjectScriptsWithMarkerInterface || script is INeedInjection) &&
                    !(script is IExcludeFromSceneInjection))
                {
                    List <InjectionData> injectionDatas = UniInjectUtils.GetInjectionDatas(script.GetType());
                    if (injectionDatas.Count > 0)
                    {
                        scriptsThatNeedInjection.Add(script);
                    }
                }
            }

            foreach (Transform child in gameObject.transform)
            {
                AnalyzeScriptsRecursively(child.gameObject);
            }
        }
コード例 #8
0
        public void DoInjection()
        {
            Stopwatch stopwatch = CreateAndStartStopwatch();

            sceneInjector = UniInjectUtils.CreateInjector();
            UniInjectUtils.SceneInjector = sceneInjector;

            // Try to find a UIDocument
            GameObject uiDocumentGameObject = GameObject.FindGameObjectWithTag("UIDocument");

            if (uiDocumentGameObject != null)
            {
                UIDocument uiDocument = uiDocumentGameObject.GetComponent <UIDocument>();
                if (uiDocument != null)
                {
                    sceneInjector.RootVisualElement = uiDocument.rootVisualElement;
                }
            }

            // Bind the scene injector itself.
            // This way it can be injected at the scene start
            // and be used to inject newly created scripts at runtime.
            sceneInjector.AddBindingForInstance(sceneInjector);

            // (1) Iterate over scene hierarchy, thereby
            // (a) find IBinder instances.
            // (b) find scripts that need injection and how their members should be injected.
            AnalyzeScene();

            // (2) Store bindings in the sceneInjector
            CreateBindings();

            // (3) Inject the bindings from the sceneInjector into the objects that need injection.
            InjectScriptsThatNeedInjection();

            StopAndLogTime(stopwatch, $"SceneInjectionManager - Analyzing, binding and injecting scene took {stopwatch.ElapsedMilliseconds} ms");

            // (4) Notify listeners that scene injection has finished
            foreach (ISceneInjectionFinishedListener listener in sceneInjectionFinishedListeners)
            {
                listener.OnSceneInjectionFinished();
            }
        }