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))); }
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(); } }