Example #1
0
        private object GetCore(Type type, Node visited = null)
        {
            if (this.bindings != null &&
                this.bindings.TryGetValue(type, out object bound))
            {
                if (bound is Type boundType)
                {
                    return(type == boundType
                               ? this.created.GetOrAdd(type, t => this.Create(t, Ctor.GetFactory(type), visited))
                               : this.GetCore(boundType, visited));
                }

                if (bound is IFactory factory)
                {
                    return(this.created.GetOrAdd(type, t => this.Create(t, factory, visited)));
                }

                return(bound);
            }

            if (type.IsInterface || type.IsAbstract)
            {
                var mapped = TypeMap.GetMapped(type);
                if (mapped.Count == 0)
                {
                    throw new NoBindingException(type, mapped);
                }

                if (mapped.Count > 1)
                {
                    throw new AmbiguousBindingException(type, mapped);
                }

                if (mapped[0].IsGenericType && !type.IsGenericType)
                {
                    throw new AmbiguousGenericBindingException(type, mapped);
                }

                return(this.GetCore(mapped[0], visited));
            }
            else
            {
                var mapped = TypeMap.GetMapped(type);
                if (mapped.Count != 0)
                {
                    throw new AmbiguousBindingException(type, mapped);
                }
            }

            return(this.created.GetOrAdd(type, t => this.Create(t, Ctor.GetFactory(type), visited)));
        }
Example #2
0
        private object Resolve(Type type, HashSet <Type> alreadyVisited, Stack <Type> explicitStack)
        {
            explicitStack.Push(type);
            try
            {
                alreadyVisited.Add(type);

                if (this.bindings.TryGetValue(type, out Type bound))
                {
                    return(this.map.GetOrAdd(bound, t => this.Resolve(t, alreadyVisited, explicitStack)));
                }

                if (type.IsInterface ||
                    type.IsAbstract)
                {
                    var mapped = TypeMap.GetMapped(type);
                    if (mapped.Count == 0)
                    {
                        throw new InvalidOperationException($"Type {type.PrettyName()} has no bindings.");
                    }

                    if (mapped.Count > 1)
                    {
                        throw new InvalidOperationException(
                                  $"Type {type.PrettyName()} has more than one binding {string.Join(",", mapped.Select(t => t.PrettyName()))}.");
                    }

                    if (mapped[0].IsGenericType && !type.IsGenericType)
                    {
                        throw new InvalidOperationException(
                                  $"Type {type.PrettyName()} has more than one binding {string.Join(",", mapped.Select(t => t.PrettyName()))}.");
                    }

                    return(this.map.GetOrAdd(mapped[0], t => this.Resolve(t, alreadyVisited, explicitStack)));
                }

                var info = Ctor.GetInfo(type);
                this.Resolving?.Invoke(this, type);
                if (info.ParameterTypes.Count == 0)
                {
                    return(info.Ctor.Invoke(null));
                }

                var args = new object[info.ParameterTypes.Count];
                for (var i = 0; i < info.ParameterTypes.Count; i++)
                {
                    if (alreadyVisited.Contains(info.ParameterTypes[i]))
                    {
                        explicitStack.Push(info.ParameterTypes[i]);
                        throw new InvalidOperationException(
                                  $"Circular dependency detected {string.Join(" -> ", explicitStack.Reverse().Select(t => t.PrettyName()))}");
                    }

                    args[i] = this.map.GetOrAdd(
                        info.ParameterTypes[i],
                        t => this.Resolve(t, alreadyVisited, explicitStack));
                }

                return(info.Ctor.Invoke(args));
            }
            finally
            {
                explicitStack.Pop();
            }
        }