Container

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

 

posted @ 2018-10-10 13:59  RR幻影  Views(167)  Comments(0Edit  收藏  举报