手写一个DI容器

发布时间 2023-04-18 09:28:40作者: Agreoself
public class MyContainer
    {
        private readonly Dictionary<Type, object> services = new Dictionary<Type, object>();

        public void Register<T>(T service)
        {
            services[typeof(T)] = service;
        }

        public T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }

        private object Resolve(Type type)
        {
            if (services.TryGetValue(type, out object service))
            {
                return service;
            }

            if (type.IsAbstract || type.IsInterface)
            {
                throw new InvalidOperationException($"Cannot resolve {type.FullName}.");
            }

            ConstructorInfo[] ctors = type.GetConstructors();
            if (ctors.Length != 1)
            {
                throw new InvalidOperationException($"Type {type.FullName} must have a single constructor.");
            }

            ConstructorInfo ctor = ctors[0];
            ParameterInfo[] parameters = ctor.GetParameters();
            object[] args = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                args[i] = Resolve(parameters[i].ParameterType);
            }

            return Activator.CreateInstance(type, args);
        }
    }

第二种反射写法

public class MyContainer
    {
        private readonly Dictionary<Type, Type> _registrations = new Dictionary<Type, Type>();

        public void Register<TFrom, TTo>() where TTo : TFrom
        {
            _registrations[typeof(TFrom)] = typeof(TTo);
        }

        public T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }

        private object Resolve(Type type)
        {
            Type implementationType = GetImplementationType(type);
            ConstructorInfo ctor = implementationType.GetConstructors()[0];
            ParameterInfo[] parameters = ctor.GetParameters();
            object[] arguments = parameters.Select(p => Resolve(p.ParameterType)).ToArray();

            return Activator.CreateInstance(implementationType, arguments);
        }

        private Type GetImplementationType(Type interfaceType)
        {
            if (!_registrations.TryGetValue(interfaceType, out Type implementationType))
            {
                implementationType = interfaceType;
            }

            if (!implementationType.IsInterface && !implementationType.IsAbstract)
            {
                return implementationType;
            }

            Type[] types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .Where(p => interfaceType.IsAssignableFrom(p) && !p.IsAbstract)
                .ToArray();

            if (types.Length > 1)
            {
                throw new InvalidOperationException($"Too many implementations of interface {interfaceType.FullName} found.");
            }

            if (types.Length == 0)
            {
                throw new InvalidOperationException($"No implementation of interface {interfaceType.FullName} found.");
            }

            return types[0];
        }
    }