• 重新整理.net core 计1400篇[六] (.net core 一个简易版的依赖注入容器 )


    前言

    我们了解到一个依赖注入的形式是:

    注入依赖服务:var root = new Cat().Register<IFoo, Foo>(Lifetime.Transient);

    获取对应的实例:

    GetServices(cat1);

    那么这个是如何实现的呢?

    看第一个new Cat()这时候做了什么?

    public class Cat : IServiceProvider, IDisposable
    {
    internal readonly Cat _root;
    internal readonly ConcurrentDictionary<Type, ServiceRegistry> _registries;
    private readonly ConcurrentDictionary<Key, object> _services;
    private readonly ConcurrentBag<IDisposable> _disposables;
    private volatile bool _disposed;
    
    public Cat()
    {
    	_registries = new ConcurrentDictionary<Type, ServiceRegistry>();
    	_root = this;
    	_services = new ConcurrentDictionary<Key, object>();
    	_disposables = new ConcurrentBag<IDisposable>();
    }
    

    这里可能有一些人没有接触过ConcurrentDictionary和 ConcurrentBag,

    这两个分别是线性安全的dictionary和list。是的,因为我们的ioc可能在不同线程中处理对象,那么这个时候是需要lock的,但是lock效率并不高,具体怎么实现的可以去看源码。

    现在我们知道在cat创建的时候呢,会创建一个注册字典,一个服务字典,一个垃圾回收list。

    下面就是去注册服务:

    public static Cat Register<TFrom, TTo>(this Cat cat, Lifetime lifetime) where TTo : TFrom
                => cat.Register(typeof(TFrom), typeof(TTo), lifetime);
    
    具体的实现:
    public static Cat Register(this Cat cat, Type from, Type to, Lifetime lifetime)
            {
                Func<Cat, Type[], object> factory = (_, arguments) => Create(_, to, arguments);
                cat.Register(new ServiceRegistry(from, lifetime, factory));
                return cat;
            }
    

    解释一下过程:创建一个用来工厂去生产to。
    new ServiceRegistry(from, lifetime, factory)
    将服务注册对象中中,封装from,生命周期,和生产to的工厂。

    这里面的作用:

    列如GetServices(cat1);,那么其获取到Foo的步骤为,通过IFOO找到对应的注册服务,然后通过注册服务去生产Foo。

    关注一下cat.Register(new ServiceRegistry(from, lifetime, factory));:

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

    这里面是什么意思呢?

    因为你可以注册Register<IFoo, Foo>,那么你也可以注册Register<IFoo, Foo1>,也就是说一个IFoo,可以对应多个实例。

    当前保存的方式通过链表的方式存储。

    这时候其实就注册完了,那么使用的时候如何使用?

    GetServices(cat1);是如何创建出Foo的呢?

    void GetServices<TService>(Cat cat)
    {
          cat.GetService<TService>();
    }
    

    具体实现:

    public object GetService(Type serviceType)
    {
    	EnsureNotDisposed();
    
    	if (serviceType == typeof(Cat) || serviceType == typeof(IServiceProvider))
    	{
    		return this;
    	}
    
    	ServiceRegistry registry;
    	//IEnumerable<T>
    	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();
    		var services = registries.Select(it => GetServiceCore(it, Type.EmptyTypes)).ToArray();
    		Array array = Array.CreateInstance(elementType, services.Length);
    		services.CopyTo(array, 0);
    		return array;
    	}
    
    	//Generic
    	if (serviceType.IsGenericType && !_registries.ContainsKey(serviceType))
    	{
    		var definition = serviceType.GetGenericTypeDefinition();
    		return _registries.TryGetValue(definition, out registry)
    			? GetServiceCore(registry, serviceType.GetGenericArguments())
    			: null;
    	}
    
    	//Normal
    	return _registries.TryGetValue(serviceType, out registry)
    			? GetServiceCore(registry, new Type[0])
    			: null;
    }
    

    第一种就是:IEnumerable<>这种,获取其泛型参数,然后创建IEnumerable<>

    第二种是这种:dictionary<string,string>,如果没有找到的话,那么会去找:dictionary<Tkey,Tvalue>

    第三种就属于普通模式了,来看下GetServiceCore。

    private object GetServiceCore(ServiceRegistry registry, Type[] genericArguments)
    {
    	var key = new Key(registry, genericArguments);
    	var serviceType = registry.ServiceType;
    
    	switch (registry.Lifetime)
    	{
    		case Lifetime.Root:return GetOrCreate(_root._services, _root._disposables);
    		case Lifetime.Self: return GetOrCreate(_services, _disposables);
    		default:
    			{
    				var service = registry.Factory(this, genericArguments);
    				if (service is IDisposable disposable && disposable != this)
    				{
    					_disposables.Add(disposable);
    				}
    				return service;
    			}
    	}
    
    	object GetOrCreate(ConcurrentDictionary<Key, object> services, ConcurrentBag<IDisposable> disposables)
    	{
    		if (services.TryGetValue(key, out var service))
    		{
    			return service;
    		}
    		service = registry.Factory(this, genericArguments);
    		services[key] = service;
    		if (service is IDisposable disposable)
    		{
    			disposables.Add(disposable);
    		}
    		return service;
    	}
    }
    

    上面源码很好理解:

    生成一个key,这个key用来保存当前注册服务和genericArguments。

    保存这个的作用在于处理单例模式。

    下面有几种模式,一种是_root 模式,因为当前依赖注入可以创建多个实例,但是只有一个是根实例。

    var cat1 = root.CreateChild();
    
    public static Cat CreateChild(this Cat cat) => new Cat(cat);
    
    internal Cat(Cat parent)
    {
    	_root = parent._root;
    	_registries = _root._registries;
    	_services = new ConcurrentDictionary<Key, object>();
    	_disposables = new ConcurrentBag<IDisposable>();
    }
    

    第二种就是:Lifetime.Self

    获取当前cat的单例模式。

    第三种就是每次都创建一个。

  • 相关阅读:
    python --异常处理
    Python -- 函数对象
    python --循环对象
    python --循环设计
    python --模块
    python --文本文件的输入输出
    xpee.vbs
    oracle 有个xe版本
    POI对Excel单元格进行颜色设置
    POI进行ExcelSheet的拷贝
  • 原文地址:https://www.cnblogs.com/aoximin/p/12914825.html
Copyright © 2020-2023  润新知