Beispiel #1
0
 public virtual bool IsScoped(Type abs)
 {
     return(IsRegistered(abs)
         ? ScopedInstances.ContainsKey(abs)
         : throw new InvalidOperationException(
                $"Тип {abs.FullName} не зарегистрирован в контейнере."));
 }
Beispiel #2
0
        public virtual object Resolve(Type abs)
        {
            abs = abs ?? throw new ArgumentNullException(nameof(abs));

            if (!RegisteredTypes.ContainsKey(abs))
            {
                throw new NotSupportedException(
                          $"Тип {abs.FullName} не зарегистрирован в контейнере.");
            }

            if (Singletons.TryGetValue(abs, out var singleton) && singleton != null)
            {
                return(singleton);
            }

            if (ScopedInstances.TryGetValue(abs, out var scoped) && scoped != null)
            {
                return(scoped);
            }

            var imp        = RegisteredTypes[abs];
            var ctorInfo   = imp.GetConstructors().Single();
            var parameters = ctorInfo.GetParameters();
            var args       = parameters.Select(p => Resolve(p.ParameterType)).ToArray();
            var instance   = Activator.CreateInstance(imp, args);

            if (Singletons.ContainsKey(abs))
            {
                Singletons[abs] = instance;
            }
            else if (ScopedInstances.ContainsKey(abs))
            {
                ScopedInstances[abs] = instance;
            }

            return(instance);
        }
Beispiel #3
0
        public void RegisterScoped(Type abs, Type imp, bool rewrite = false)
        {
            var hasKey = ScopedInstances.TryGetValue(abs, out var oldValue);

            if (!hasKey)
            {
                ScopedInstances.Add(abs, null);
            }
            else if (rewrite)
            {
                oldValue             = ScopedInstances[abs];
                ScopedInstances[abs] = null;
            }
            else
            {
                throw new InvalidOperationException(
                          $"Тип {abs.FullName} уже зарегистрирован как синглтон для экземпляра контейнера.");
            }

            try
            {
                RegisterTransient(abs, imp, rewrite);
            }
            catch
            {
                if (!hasKey)
                {
                    ScopedInstances.Remove(abs);
                }
                else
                {
                    ScopedInstances[abs] = oldValue;
                }

                throw;
            }
        }
Beispiel #4
0
        public virtual void RegisterTransient(Type abs, Type imp, bool rewrite = false)
        {
            abs = abs ?? throw new ArgumentNullException(nameof(abs));
            imp = imp ?? throw new ArgumentNullException(nameof(imp));

            if (!imp.IsClass)
            {
                throw new NotSupportedException(
                          $"Тип {imp.FullName} не является классом.");
            }

            if (!rewrite && RegisteredTypes.ContainsKey(abs))
            {
                throw new InvalidOperationException(
                          $"Тип {abs.FullName} уже зарегистрирован в контейнере.");
            }

            if (!abs.IsAssignableFrom(imp))
            {
                throw new InvalidOperationException(
                          $"Тип {imp.FullName} не может быть приведён к типу {abs.FullName}.");
            }

            var foundTypes = new List <Type>();

            if (!Singletons.ContainsKey(abs) && !ScopedInstances.ContainsKey(abs))
            {
                foundTypes.Add(abs);
            }

            if (!Singletons.ContainsKey(imp) && !ScopedInstances.ContainsKey(imp) && !foundTypes.Contains(imp))
            {
                foundTypes.Add(imp);
            }

            void CheckRecursion(Type type)
            {
                var ctors = type.GetConstructors();

                if (ctors.Length != 1)
                {
                    throw new NotSupportedException(
                              $"Неразрешимая зависимость: контейнер не может выбрать вызываемый конструктор для типа {type.FullName}.");
                }

                var constructorInfo = ctors.Single();

                var parameterTransientTypes = constructorInfo.GetParameters()
                                              .Select(p => p.ParameterType)
                                              .Except(Singletons.Keys)
                                              .Except(ScopedInstances.Keys)
                                              .Distinct()
                                              .ToArray();

                foreach (var parameterType in parameterTransientTypes)
                {
                    if (foundTypes.Contains(parameterType))
                    {
                        throw new NotSupportedException(
                                  $"Неразрешимая зависимость: циклическая зависимость для типа {type.FullName} в типе параметра {parameterType.FullName}.");
                    }

                    if (parameterType.IsClass)
                    {
                        CheckRecursion(parameterType);
                    }
                }

                foundTypes.AddRange(parameterTransientTypes);
            }

            CheckRecursion(imp);

            RegisteredTypes[abs] = imp;
        }