internal struct CachedTypeInfo { public Type Type; public bool IsSingleton; }
internal class ConstructorCache { private static ConcurrentDictionary<Type, ConstructorInfo> _constructorCache = new ConcurrentDictionary<Type, ConstructorInfo>(); public static ConstructorInfo GetConstructor(Type type) { ConstructorInfo constructor; if (!_constructorCache.TryGetValue(type, out constructor)) constructor = _constructorCache[type] = DiscoverConstructor(type.GetTypeInfo()); return constructor; } private static ConstructorInfo DiscoverConstructor(TypeInfo typeInfo) { var constructors = typeInfo.DeclaredConstructors; if (constructors.Any()) return constructors.First(); return null; } }
public interface IContainer : IServiceProvider { void Register<TService, TImplementation>() where TImplementation : TService; void Register<TService, TImplementation>(bool singleton) where TImplementation : TService; void Register<TService>(Type implementation, bool singleton); void Register<TService>(Type implementation, Action<TService> callback, bool singleton); void Register(Type service, Type implementation, bool singleton); void Register<TService>(TService instance); T Resolve<T>(); bool IsRegistered<T>(); }
internal class ParameterCache { private static ConcurrentDictionary<ConstructorInfo, List<ParameterInfo>> _parameterCache = new ConcurrentDictionary<ConstructorInfo, List<ParameterInfo>>(); public static List<ParameterInfo> GetParameters(ConstructorInfo constructor) { List<ParameterInfo> parameterInfo; if (!_parameterCache.TryGetValue(constructor, out parameterInfo)) { // Not in cache, discover and add to cache. parameterInfo = _parameterCache[constructor] = DiscoverParameters(constructor); } return parameterInfo; } private static List<ParameterInfo> DiscoverParameters(ConstructorInfo constructor) { return constructor.GetParameters().ToList(); } }
public class SimpleContainer : IContainer { private readonly ConcurrentDictionary<Type, CachedTypeInfo> _serviceTypeLookup = new ConcurrentDictionary<Type, CachedTypeInfo>(); private readonly ConcurrentDictionary<Type, object> _serviceInstanceLookup = new ConcurrentDictionary<Type, object>(); private readonly ConcurrentDictionary<Type, Action<object>> _serviceTypeCallbackLookup = new ConcurrentDictionary<Type, Action<object>>(); #region IContainer Implementation public void Register<TService, TImplementation>() where TImplementation : TService { _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = typeof(TImplementation), IsSingleton = true }; } public void Register<TService, TImplementation>(bool singleton = true) where TImplementation : TService { _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = typeof(TImplementation), IsSingleton = singleton }; } public void Register<TService>(Type implementationType, bool singleton = true) { if (implementationType == null) throw new ArgumentNullException("implementationType cannot be null."); _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton }; } public void Register<TService>(Type implementationType, Action<TService> callback, bool singleton = true) { if (implementationType == null) throw new ArgumentNullException("serviceType cannot be null."); _serviceTypeLookup[typeof(TService)] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton }; if (callback != null) _serviceTypeCallbackLookup[typeof(TService)] = (x) => callback((TService)x); } public void Register(Type serviceType, Type implementationType, bool singleton = true) { if (serviceType == null) throw new ArgumentNullException("serviceType cannot be null."); if (implementationType == null) throw new ArgumentNullException("serviceType cannot be null."); if (!serviceType.IsAssignableFrom(implementationType)) throw new ArgumentException(string.Format("Service could not be registered. {0} does not implement {1}.", implementationType.Name, serviceType.Name)); _serviceTypeLookup[serviceType] = new CachedTypeInfo { Type = implementationType, IsSingleton = singleton }; } public void Register<TService>(TService instance) { if (instance == null) throw new ArgumentNullException("instance cannot be null."); _serviceInstanceLookup[typeof(TService)] = instance; } public T Resolve<T>() { return (T)Resolve(typeof(T)); } private object Resolve(Type type) { CachedTypeInfo containerType; object instance = null; // If the type isn't registered, register the type to itself. if (!_serviceTypeLookup.TryGetValue(type, out containerType)) { Register(type, type); containerType = new CachedTypeInfo { Type = type, IsSingleton = true }; } // TODO: Should it use the instance by default? I'd assume so initially. // Check if the service has an instance in the list of instances, if so, return it here. if (_serviceInstanceLookup.TryGetValue(type, out instance)) return instance; var constructor = ConstructorCache.GetConstructor(containerType.Type); if (constructor != null) { // Get constructor parameters. var parameters = ParameterCache.GetParameters(constructor); var parameterObjects = new List<object>(); foreach (var parameter in parameters) { parameterObjects.Add(Resolve(parameter.ParameterType)); } var obj = Activator.CreateInstance(containerType.Type, parameterObjects.ToArray()); Action<object> callback; if (_serviceTypeCallbackLookup.TryGetValue(type, out callback)) callback(obj); if (containerType.IsSingleton) _serviceInstanceLookup[type] = obj; return obj; } else { // Return null rather than throw an exception for resolve failures. // This null will happen when there are 0 constructors for the supplied type. return null; } } public bool IsRegistered<TService>() { if (_serviceTypeLookup.ContainsKey(typeof(TService)) || _serviceInstanceLookup.ContainsKey(typeof(TService))) return true; return false; } #endregion #region IServiceProvider Implementation public object GetService(Type serviceType) { return Resolve(serviceType); } #endregion }
internal static class TypeResolver { private static ConcurrentDictionary<Type, Type> _typeCache = new ConcurrentDictionary<Type, Type>(); public static Type Resolve<T>(string className) { var type = typeof(T); Type implementationType = null; if (!_typeCache.TryGetValue(type, out implementationType)) { implementationType = _typeCache[type] = Resolve(className, type); } return implementationType; } public static Type Resolve(string implementingType, Type serviceType = null) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var types = assemblies.SelectMany(a => a.GetTypes()); Type type = null; if (serviceType != null) type = types.FirstOrDefault(t => t.Name == implementingType && serviceType.IsAssignableFrom(t)); else type = types.FirstOrDefault(t => t.Name == implementingType); return type; } }