Core源码(八)依赖注入

依赖注入的源码是Microsoft.Extensions.DependencyInjection命名空间下的,项目结构比较复杂,本文先从先从简单的实现开始,一起了解下依赖注入最基础的实现

最基础的依赖注入

依赖注入容器

public class Cat
{
    /// <summary>
    /// 线程安全的集合去保存所有的类型
    /// </summary>
    private ConcurrentDictionary<Type, Type> typeMapping = new ConcurrentDictionary<Type, Type>();
    //注册到容器中
    public void Register(Type from, Type to)
    {
        typeMapping[from] = to;
    }

    //这个是核心方法
    public object GetService(Type serviceType)
    {
        #region 构造函数注入

        Type type;
        if (!typeMapping.TryGetValue(serviceType, out type))
        {
            type = serviceType;
        }
        if (type.IsInterface || type.IsAbstract)
        {
            return null;
        }
        //获取构造函数的基本信息
        ConstructorInfo constructor = this.GetConstructor(type);
        if (null == constructor)
        {
            return null;
        }
        //这里递归的获取了所有需要的实例
        object[] arguments = constructor.GetParameters().Select(p => GetService(p.ParameterType)).ToArray();
        //根据获得的参数调用构造函数 得到所需对象service
        object service = constructor.Invoke(arguments);
        
        #endregion

        return service;
    }

    /// <summary>
    /// 获取对应类型的构造器
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    protected virtual ConstructorInfo GetConstructor(Type type)
    {
        ConstructorInfo[] constructors = type.GetConstructors();
        //如果我们有标记了InjectionAttribute 那么就用标记了的构造器
        return constructors.FirstOrDefault(c => c.GetCustomAttribute<InjectionAttribute>() != null)
            ?? constructors.FirstOrDefault();
    }
}

扩展方法

public static class CatExtensions
{
    public static T GetService<T>(this Cat cat)
    {
        if (cat == null)
        {
            throw new ArgumentNullException("collection");
        }
        return (T)cat.GetService(typeof(T));
    }

    public static void Register<TService, TImplementation>(this Cat cat)
    {
        if (cat == null)
        {
            throw new ArgumentNullException("collection");
        }
        cat.Register(typeof(TService), typeof(TImplementation));
    }
}

实际使用

public interface IFoo { }
public interface IBar { }
public class Bar : IBar { }
public class Foo : IFoo
{
    public IBar Bar { get; private set; }
    public Foo() { }
    [Injection]
    public Foo(IBar bar)
    {
        this.Bar = bar;
    }
}
main方法
Cat cat = new Cat();
cat.Register<IFoo, Foo>();
cat.Register<IBar, Bar>();

IFoo service = cat.GetService<IFoo>();
Foo foo = (Foo)service;
Console.WriteLine("cat.GetService<IFoo>(): {0}", service);
Console.WriteLine("cat.GetService<IFoo>().Bar: {0}", foo.Bar);

这里我们通过public class InjectionAttribute : Attribute { } 标记需要注入的构造函数,然后我们简单的容器就会根据特性去选择对应执行的构造方法。

带有实例生命周期管理的依赖注入

ServiceRegistry

使用ServiceRegistry类进行服务注册的基础单元,我们将针对同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表,作为相邻节点的两个ServiceRegistry对象通过Next属性关联起来。我们为ServiceRegistry定义了一个AsEnumerable方法是它返回由当前以及后续节点组成的ServiceRegistry集合。

public enum Lifetime
{
    Singlelton,
    Self,
    Transient
}
public class ServiceRegistry
{
    public Type ServiceType { get; }
    public Lifetime Lifetime { get; }
    /// <summary>
    /// core的依赖注入还有实例模式,这里只有工厂模式做展示
    /// </summary>
    public Func<Cat, Type[], object> Factory { get; }
    /// <summary>
    /// 同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表
    /// </summary>
    internal ServiceRegistry Next { get; set; }

    public ServiceRegistry(Type serviceType, Lifetime lifetime, Func<Cat, Type[], object> factory)
    {
        ServiceType = serviceType;
        Lifetime = lifetime;
        Factory = factory;
    }

    public IEnumerable<ServiceRegistry> AsEnumerable()
    {
        var list = new List<ServiceRegistry>();
        for (var self = this; self != null; self = self.Next)
        {
            list.Add(self);
        }
        return list;
    }
}

ServiceRegistry

主容器Cat

public class Cat : IServiceProvider, IDisposable
{
    internal Cat _root;
    /// <summary>
    /// 类型注册到容器中时候,用来存储的集合
    /// </summary>
    internal ConcurrentDictionary<Type, ServiceRegistry> _registries;
    /// <summary>
    /// 获取类型实例的集合
    /// </summary>
    private ConcurrentDictionary<ServiceRegistry, object> _services;
    private ConcurrentBag<IDisposable> _disposables;
    /// <summary>
    ///  Dispose()时候设置为true
    /// </summary>
    private volatile bool _disposed;

    /// <summary>
    /// 根容器的构造函数
    /// </summary>
    public Cat()
    {
        _registries = new ConcurrentDictionary<Type, ServiceRegistry>();
        _root = this;
        _services = new ConcurrentDictionary<ServiceRegistry, object>();
        _disposables = new ConcurrentBag<IDisposable>();
    }

    /// <summary>
    /// 创建子容器的构造函数
    /// </summary>
    /// <param name="parent"></param>
    internal Cat(Cat parent)
    {
        _root = parent._root;
        _registries = _root._registries;
        _services = new ConcurrentDictionary<ServiceRegistry, object>();
        _disposables = new ConcurrentBag<IDisposable>();
    }

    public Cat Register(ServiceRegistry registry)
    {
        EnsureNotDisposed();
        //判断是否有同类型的注册
        if (_registries.TryGetValue(registry.ServiceType, out var existing))
        {
            _registries[registry.ServiceType] = registry;
            registry.Next = existing;
        }
        else
        {
            _registries[registry.ServiceType] = registry;
        }
        return this;
    }

    /// <summary>
    /// 如果没注册过类型,会返回null
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public object GetService(Type serviceType)
    {
        EnsureNotDisposed();
        if (serviceType == typeof(Cat))
        {
            return this;
        }
        ServiceRegistry registry;
        if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            var elementType = serviceType.GetGenericArguments()[0];
            if (!_registries.TryGetValue(elementType, out  registry))
            {
                //没有就直接创建
                return Array.CreateInstance(elementType, 0);
            }

            var registries = registry.AsEnumerable();
            object[] services = registries.Select(it => GetServiceCore(it, new Type[0])).ToArray();
            //创建一个数组,然后把所有注册到容器中的工厂方法的实例返回
            Array array = Array.CreateInstance(elementType, services.Length);
            services.CopyTo(array, 0);
            return array;
        }

        if (serviceType.IsGenericType && !_registries.ContainsKey(serviceType))
        {
            var definition = serviceType.GetGenericTypeDefinition();
            return _registries.TryGetValue(definition, out registry)
                //泛型需要获取对应类型参数
                ? GetServiceCore(registry, serviceType.GetGenericArguments())
                : null;
        }

        return _registries.TryGetValue(serviceType, out registry)
                ? GetServiceCore(registry, new Type[0])
                : null;
    }

    /// <summary>
    /// 实际进行实例创造的方法
    /// </summary>
    /// <param name="registry"></param>
    /// <param name="genericArguments"></param>
    /// <returns></returns>
    private object GetServiceCore(ServiceRegistry registry, Type[] genericArguments)
    {
        var serviceType = registry.ServiceType;
        //方法内部的方法,我还真的很少这么写。
        object GetOrCreate(ConcurrentDictionary<ServiceRegistry, object> services, ConcurrentBag<IDisposable> disposables)
        {
            if (services.TryGetValue(registry, out var service))
            {
                return service;
            }
            service = registry.Factory(this, genericArguments);
            services[registry] = service;
            var disposable = service as IDisposable;
            if (null != disposable)
            {
                disposables.Add(disposable);
            }
            return service;
        }

        switch (registry.Lifetime)
        {
            case Lifetime.Singlelton: return GetOrCreate(_root._services, _root._disposables);   
            case Lifetime.Self: return GetOrCreate(_services, _disposables);
            default:
                //如果是Transient类型,直接创建实例,然后判断是否是IDisposable,如果是加入IDisposable数组
                //会在容器Disposable时候,遍历Disposable
                {
                    var service = registry.Factory(this, genericArguments);
                    var disposable = service as IDisposable;
                    if (null != disposable)
                    {
                        _disposables.Add(disposable);
                    }
                    return service;
                }
        }
    }

    public void Dispose()
    {
        _disposed = true;
        foreach(var disposable in _disposables)
        {
            disposable.Dispose();
        }
        while (!_disposables.IsEmpty)
        {
            _disposables.TryTake(out _);
        }
        _services.Clear();
    }

    private void EnsureNotDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException("Cat");
        }
    }
}

Cat

主容器的扩展方法

public static class CatExtensions
{
    public static IEnumerable<T> GetServices<T>(this Cat cat) => cat.GetService<IEnumerable<T>>();
    public static T GetService<T>(this Cat cat) => (T)cat.GetService(typeof(T));
    public static bool HasRegistry<T>(this Cat cat) => cat.HasRegistry(typeof(T));
    public static bool HasRegistry(this Cat cat, Type serviceType) => cat._root._registries.ContainsKey(serviceType);
    public static Cat Register(this Cat cat, Type from, Type to, Lifetime lifetime)
    {
        Func<Cat, Type[], object> factory = (x, arguments) => Create(x, to, arguments);
        cat.Register(new ServiceRegistry(from, lifetime, factory));
        return cat;
    }
    public static Cat Register<TFrom, TTo>(this Cat cat, Lifetime lifetime)
        where TTo : TFrom
    {
        Func<Cat, Type[], object> factory = (_, arguments) => Create(_, typeof(TTo), arguments);
        cat.Register(new ServiceRegistry(typeof(TFrom), lifetime, factory));
        return cat;
    }

    public static Cat Register<TServiceType>(this Cat cat, TServiceType instance)
    {
        Func<Cat, Type[], object> factory = (_, arguments) => instance;
        cat.Register(new ServiceRegistry(typeof(TServiceType), Lifetime.Singlelton, factory));
        return cat;
    }

    public static Cat Register<TServiceType>(this Cat cat, Func<Cat, TServiceType> factory, Lifetime lifetime)
    {
        cat.Register(new ServiceRegistry(typeof(TServiceType), lifetime, (_, arguments) => factory(_)));
        return cat;
    }

    public static Cat CreateChild(this Cat cat) => new Cat(cat);

    private static object Create(Cat cat, Type type, Type[] genericArguments)
    {
        if (genericArguments.Length > 0)//是泛型的情况下
        {
            //生成泛型类型
            type = type.MakeGenericType(genericArguments);
        }
        var constructors = type.GetConstructors();
        if (constructors.Length == 0)//没有构造函数的情况下
        {
            throw new InvalidOperationException($"Cannot create the instance of {type} which does not have an public constructor.");
        }
        var constructor = constructors.FirstOrDefault(it => it.GetCustomAttributes(false).OfType<InjectionAttribute>().Any());
        //空的时候用第一个
        constructor = constructor ?? constructors.First();
        var parameters = constructor.GetParameters();
        if (parameters.Length == 0)
        {
            return Activator.CreateInstance(type);
        }
        var arguments = new object[parameters.Length];
        //递归调用所有的parameters
        for (int index = 0; index < arguments.Length; index++)
        {
            var parameter = parameters[index];
            var parameterType = parameter.ParameterType;
            if (cat.HasRegistry(parameterType))
            {
                arguments[index] = cat.GetService(parameterType);
            }
            else if (parameter.HasDefaultValue)
            {
                arguments[index] = parameter.DefaultValue;
            }
            else//没有注册也没有默认的情况下,会抛出异常
            {
                throw new InvalidOperationException($"Cannot create the instance of {type} whose constructor has non-registered parameter type(s)");
            }
        }
        return Activator.CreateInstance(type, arguments);
    }
}

CatExtensions

Core依赖注入

CORE框架的依赖注入实现肯定比我们以上的实现复杂很多,他里面有实例的生命周期管理,ServiceProvider树等。

       不过最基本的体系在我们上面的例子中都已经有介绍。

       本文参考Artech大神的依赖注入文章和core源码。

相关推荐