using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using MicroIoc; namespace MicroIoc { public class MicroIocContainer : IMicroIocContainer { private readonly Dictionary, Func> _resolverDictionary = new Dictionary, Func>(); private readonly IList _registeredSingletons = new List(); private readonly Dictionary _singletonInstances = new Dictionary(); private static readonly string CollectionDefaultKey = Guid.NewGuid().ToString(); #region Register /// /// Register a type within the container. Useful when registering a type by key, so calls to Resolve(null, key) will work /// /// The type of class being registered /// If specified, will associate a specific instance for this type /// Indicates if the registration should yield a singleton object when resolved /// The container, complete with new registration public IMicroIocContainer Register(string key = null, bool isSingleton = false) { return Register(key, isSingleton); } /// /// Register an implementation type against an interface or class /// /// The type of interface or class to be registered /// The type of concrete class to be instantiated when is resolved from the container. /// The container, complete with new registration public IMicroIocContainer Register(string key = null, bool isSingleton = false) where TTo : TFrom { key = ValueOrDefault(key); var fromType = typeof(TFrom); var toType = typeof(TTo); if (isSingleton) _registeredSingletons.Add(toType); _resolverDictionary[new Tuple(fromType, key)] = () => BuildFromType(toType); return this; } /// /// Register a specific instance of a concrete implementation for an interface or class /// /// The type of interface or class to be registered /// The instance to register in the container /// (Optional) a key to specify the instance within the container /// The container, complete with new registration public IMicroIocContainer RegisterInstance(TInterface instance, string key = null) { return RegisterInstance(typeof (TInterface), instance, key); } public IMicroIocContainer RegisterInstance(Type type, object instance, string key=null) { key = ValueOrDefault(key); _resolverDictionary[new Tuple(type, key)] = () => instance; return this; } #endregion #region Resolve /// /// Resolve an instance of the specified interface (or class) Type /// /// The type of interface or class to be resolved /// (Optional) a key to specify the instance within the container /// The registered instance if key is specified, or a dynamically instantiated instance, if not public T Resolve(string key = null) { return (T) Resolve(typeof (T), key); } /// /// Try to resolve an instance of the specified interface (or class) Type /// /// The type of interface or class to be resolved /// (Optional) a key to specify the instance within the container /// An instance of if registered, or null public T TryResolve(string key) where T : class { return (T) TryResolve(typeof (T), key); } /// /// Resolve an instance of the specified interface (or class) Type /// /// The type of interface or class to be resolved /// (Optional) a key to specify the instance within the container /// The registered instance if key is specified, or a dynamically instantiated instance, if not public object Resolve(Type type, string key = null) { var result = ResolveCore(type, key); BuildUp(result); return result; } /// /// Try to resolve an instance of the specified interface (or class) Type /// /// The type of interface or class to be resolved /// (Optional) a key to specify the instance within the container /// An instance of if registered, or null public object TryResolve(Type type, string key) { try { return Resolve(type, key); } catch { return null; } } /// /// Resolve all registered instances of a specified type /// /// The type of interface or class to be resolved /// A collection of registered instances. If no instances are registered, returns empty collection, not null public IEnumerable ResolveAll() { var allObjects = ResolveAll(typeof (T)); return allObjects.Select(obj => (T) obj); } /// /// Resolve all registered instances of a specified type /// /// The type of interface or class to be resolved /// A collection of registered instances. If no instances are registered, returns empty collection, not null public IEnumerable ResolveAll(Type type) { return _resolverDictionary.Keys .Where(key => key.Item1 == type) .Select(t => _resolverDictionary[t]()); } #endregion /// /// Create an instance with properties from the container. /// Only properties attributed [Inject] will be set. /// /// public void BuildUp(object instance) { var propertyInfoCollection = instance.GetType().GetProperties(); foreach (var propertyInfo in propertyInfoCollection) { var info = propertyInfo; if (!info.GetCustomAttributes(typeof(InjectAttribute), false).Any()) continue; object property = null; try { var fullPropertyName = string.Format("{0}.{1}", instance.GetType().FullName, info.Name); property = Resolve(null, fullPropertyName); } catch (Exception) { property = Resolve(info.PropertyType); } finally { info.SetValue(instance, property, null); } } } public IConfiguration GetConfiguration() { return new ContainerConfiguration(this); } #region Private helper methods private object ResolveCore(Type type, string key) { if (type == null) { type = DeriveType(key); if (type == null) throw new ResolutionException("Failed to Derive type for " + key); } key = ValueOrDefault(key); return _resolverDictionary.ContainsKey(new Tuple(type, key)) ? _resolverDictionary[new Tuple(type, key)]() : BuildFromType(type); } private Type DeriveType(string key) { var result = GetTypeFromContainer(key); if (result != null) return result; // Not in the container? Try the Assembly return Assembly.GetExecutingAssembly() .GetTypes() .SingleOrDefault(t => t.Name == key); } private Type GetTypeFromContainer(string key) { var tuple = _resolverDictionary .Keys .FirstOrDefault(t => t.Item2 == key); return (tuple == null) ? null : tuple.Item1; } private object BuildFromType(Type type) { if (_registeredSingletons.Contains(type)) { object instance; if (_singletonInstances.TryGetValue(type, out instance)) return instance; instance = InstantiateInstance(type); _singletonInstances[type] = instance; return instance; } return InstantiateInstance(type); } private object InstantiateInstance(Type type) { var constructor = type.GetConstructors() .OrderByDescending(c => c.GetParameters().Length) .FirstOrDefault(); if (constructor == null) throw new ResolutionException("Could not locate a constructor for " + type.FullName); var constructorParams = new List(constructor.GetParameters().Length); foreach (var parameterInfo in constructor.GetParameters()) { object parameter=null; try { string key = type.ConstructorParamPattern(parameterInfo.Name); parameter = Resolve(null, key); } catch (Exception) { parameter = Resolve(parameterInfo.ParameterType); } finally { constructorParams.Add(parameter); } } try { return constructor.Invoke(constructorParams.ToArray()); } catch (Exception exception) { throw new ResolutionException("Failed to resolve " + type.Name, exception); } } private static string ValueOrDefault(string key) { if (key != null) key = key.Trim(); return string.IsNullOrEmpty(key) ? CollectionDefaultKey : key; } #endregion } }