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源码。
相关推荐
瓜牛呱呱 2020-11-12
柳木木的IT 2020-11-04
yifouhu 2020-11-02
lei0 2020-11-02
源码zanqunet 2020-10-26
码代码的陈同学 2020-10-14
lukezhong 2020-10-14
clh0 2020-09-18
changcongying 2020-09-17
星辰大海的路上 2020-09-13
abfdada 2020-08-26
mzy000 2020-08-24
shenlanse 2020-08-18
zhujiangtaotaise 2020-08-18
xiemanR 2020-08-17